| @@ -42,208 +42,78 @@ · 41 unmodified lines |
| 42 | #include "filters.h" | 42 | #include "filters.h" |
| 43 | #include "formats.h" | 43 | #include "formats.h" |
| 44 | #include "internal.h" | 44 | #include "internal.h" |
| | 45 | #include "af_afir.h" |
| 45 | #include "af_afirdsp.h" | 46 | #include "af_afirdsp.h" |
| 46 | | 47 | |
| 47 | typedef struct AudioFIRSegment { | 48 | static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color) |
| 48 | int nb_partitions; | 49 | { |
| 49 | int part_size; | 50 | const uint8_t *font; |
| 50 | int block_size; | 51 | int font_height; |
| 51 | int fft_length; | 52 | int i; |
| 52 | int coeff_size; | | |
| 53 | int input_size; | | |
| 54 | int input_offset; | | |
| 55 | | | |
| 56 | int *output_offset; | | |
| 57 | int *part_index; | | |
| 58 | | | |
| 59 | AVFrame *sumin; | | |
| 60 | AVFrame *sumout; | | |
| 61 | AVFrame *blockin; | | |
| 62 | AVFrame *blockout; | | |
| 63 | AVFrame *buffer; | | |
| 64 | AVFrame *coeff; | | |
| 65 | AVFrame *input; | | |
| 66 | AVFrame *output; | | |
| 67 | | | |
| 68 | AVTXContext **tx, **itx; | | |
| 69 | av_tx_fn tx_fn, itx_fn; | | |
| 70 | } AudioFIRSegment; | | |
| 71 | | | |
| 72 | typedef struct AudioFIRContext { | | |
| 73 | const AVClass *class; | | |
| 74 | | | |
| 75 | float wet_gain; | | |
| 76 | float dry_gain; | | |
| 77 | float length; | | |
| 78 | int gtype; | | |
| 79 | float ir_gain; | | |
| 80 | int ir_format; | | |
| 81 | float max_ir_len; | | |
| 82 | int response; | | |
| 83 | int w, h; | | |
| 84 | AVRational frame_rate; | | |
| 85 | int ir_channel; | | |
| 86 | int minp; | | |
| 87 | int maxp; | | |
| 88 | int nb_irs; | | |
| 89 | int selir; | | |
| 90 | | | |
| 91 | float gain; | | |
| 92 | | | |
| 93 | int eof_coeffs[32]; | | |
| 94 | int have_coeffs; | | |
| 95 | int nb_taps; | | |
| 96 | int nb_channels; | | |
| 97 | int nb_coef_channels; | | |
| 98 | int one2many; | | |
| 99 | | | |
| 100 | AudioFIRSegment seg[1024]; | | |
| 101 | int nb_segments; | | |
| 102 | | | |
| 103 | AVFrame *in; | | |
| 104 | AVFrame *ir[32]; | | |
| 105 | AVFrame *video; | | |
| 106 | int min_part_size; | | |
| 107 | int64_t pts; | | |
| 108 | | 53 | |
| 109 | AudioFIRDSPContext afirdsp; | 54 | font = avpriv_cga_font, font_height = 8; |
| 110 | AVFloatDSPContext *fdsp; | | |
| 111 | } AudioFIRContext; | | |
| 112 | | 55 | |
| 113 | static void direct(const float *in, const AVComplexFloat *ir, int len, float *out) | 56 | for (i = 0; txt[i]; i++) { |
| 114 | { | 57 | int char_y, mask; |
| 115 | for (int n = 0; n < len; n++) | | |
| 116 | for (int m = 0; m <= n; m++) | | |
| 117 | out[n] += ir[m].re * in[n - m]; | | |
| 118 | } | | |
| 119 | | 58 | |
| 120 | static void fir_fadd(AudioFIRContext *s, float *dst, const float *src, int nb_samples) | 59 | uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4; |
| 121 | { | 60 | for (char_y = 0; char_y < font_height; char_y++) { |
| 122 | if ((nb_samples & 15) == 0 && nb_samples >= 16) { | 61 | for (mask = 0x80; mask; mask >>= 1) { |
| 123 | s->fdsp->vector_fmac_scalar(dst, src, 1.f, nb_samples); | 62 | if (font[txt[i] * font_height + char_y] & mask) |
| 124 | } else { | 63 | AV_WL32(p, color); |
| 125 | for (int n = 0; n < nb_samples; n++) | 64 | p += 4; |
| 126 | dst[n] += src[n]; | 65 | } |
| | 66 | p += pic->linesize[0] - 8 * 4; |
| | 67 | } |
| 127 | } | 68 | } |
| 128 | } | 69 | } |
| 129 | | 70 | |
| 130 | static int fir_quantum(AVFilterContext *ctx, AVFrame *out, int ch, int offset) | 71 | static void draw_line(AVFrame *out, int x0, int y0, int x1, int y1, uint32_t color) |
| 131 | { | 72 | { |
| 132 | AudioFIRContext *s = ctx->priv; | 73 | int dx = FFABS(x1-x0); |
| 133 | const float *in = (const float *)s->in->extended_data[ch] + offset; | 74 | int dy = FFABS(y1-y0), sy = y0 < y1 ? 1 : -1; |
| 134 | float *blockin, *blockout, *buf, *ptr = (float *)out->extended_data[ch] + offset; | 75 | int err = (dx>dy ? dx : -dy) / 2, e2; |
| 135 | const int nb_samples = FFMIN(s->min_part_size, out->nb_samples - offset); | | |
| 136 | int n, i, j; | | |
| 137 | | | |
| 138 | for (int segment = 0; segment < s->nb_segments; segment++) { | | |
| 139 | AudioFIRSegment *seg = &s->seg[segment]; | | |
| 140 | float *src = (float *)seg->input->extended_data[ch]; | | |
| 141 | float *dst = (float *)seg->output->extended_data[ch]; | | |
| 142 | float *sumin = (float *)seg->sumin->extended_data[ch]; | | |
| 143 | float *sumout = (float *)seg->sumout->extended_data[ch]; | | |
| 144 | | | |
| 145 | if (s->min_part_size >= 8) { | | |
| 146 | s->fdsp->vector_fmul_scalar(src + seg->input_offset, in, s->dry_gain, FFALIGN(nb_samples, 4)); | | |
| 147 | emms_c(); | | |
| 148 | } else { | | |
| 149 | for (n = 0; n < nb_samples; n++) | | |
| 150 | src[seg->input_offset + n] = in[n] * s->dry_gain; | | |
| 151 | } | | |
| 152 | | | |
| 153 | seg->output_offset[ch] += s->min_part_size; | | |
| 154 | if (seg->output_offset[ch] == seg->part_size) { | | |
| 155 | seg->output_offset[ch] = 0; | | |
| 156 | } else { | | |
| 157 | memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); | | |
| 158 | | | |
| 159 | dst += seg->output_offset[ch]; | | |
| 160 | fir_fadd(s, ptr, dst, nb_samples); | | |
| 161 | continue; | | |
| 162 | } | | |
| 163 | | | |
| 164 | if (seg->part_size < 8) { | | |
| 165 | memset(dst, 0, sizeof(*dst) * seg->part_size * seg->nb_partitions); | | |
| 166 | | | |
| 167 | j = seg->part_index[ch]; | | |
| 168 | | | |
| 169 | for (i = 0; i < seg->nb_partitions; i++) { | | |
| 170 | const int coffset = j * seg->coeff_size; | | |
| 171 | const AVComplexFloat *coeff = (const AVComplexFloat *)seg->coeff->extended_data[ch * !s->one2many] + coffset; | | |
| 172 | | | |
| 173 | direct(src, coeff, nb_samples, dst); | | |
| 174 | | 76 | |
| 175 | if (j == 0) | 77 | for (;;) { |
| 176 | j = seg->nb_partitions; | 78 | AV_WL32(out->data[0] + y0 * out->linesize[0] + x0 * 4, color); |
| 177 | j--; | | |
| 178 | } | | |
| 179 | | 79 | |
| 180 | seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions; | 80 | if (x0 == x1 && y0 == y1) |
| | 81 | break; |
| 181 | | 82 | |
| 182 | memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); | 83 | e2 = err; |
| 183 | | 84 | |
| 184 | for (n = 0; n < nb_samples; n++) { | 85 | if (e2 >-dx) { |
| 185 | ptr[n] += dst[n]; | 86 | err -= dy; |
| 186 | } | 87 | x0--; |
| 187 | continue; | | |
| 188 | } | 88 | } |
| 189 | | 89 | |
| 190 | memset(sumin, 0, sizeof(*sumin) * seg->fft_length); | 90 | if (e2 < dy) { |
| 191 | blockin = (float *)seg->blockin->extended_data[ch] + seg->part_index[ch] * seg->block_size; | 91 | err += dx; |
| 192 | blockout = (float *)seg->blockout->extended_data[ch] + seg->part_index[ch] * seg->block_size; | 92 | y0 += sy; |
| 193 | memset(blockin + seg->part_size, 0, sizeof(*blockin) * (seg->fft_length - seg->part_size)); | | |
| 194 | | | |
| 195 | memcpy(blockin, src, sizeof(*src) * seg->part_size); | | |
| 196 | | | |
| 197 | seg->tx_fn(seg->tx[ch], blockout, blockin, sizeof(float)); | | |
| 198 | | | |
| 199 | j = seg->part_index[ch]; | | |
| 200 | | | |
| 201 | for (i = 0; i < seg->nb_partitions; i++) { | | |
| 202 | const int coffset = j * seg->coeff_size; | | |
| 203 | const float *blockout = (const float *)seg->blockout->extended_data[ch] + i * seg->block_size; | | |
| 204 | const AVComplexFloat *coeff = (const AVComplexFloat *)seg->coeff->extended_data[ch * !s->one2many] + coffset; | | |
| 205 | | | |
| 206 | s->afirdsp.fcmul_add(sumin, blockout, (const float *)coeff, seg->part_size); | | |
| 207 | | | |
| 208 | if (j == 0) | | |
| 209 | j = seg->nb_partitions; | | |
| 210 | j--; | | |
| 211 | } | 93 | } |
| 212 | | | |
| 213 | seg->itx_fn(seg->itx[ch], sumout, sumin, sizeof(float)); | | |
| 214 | | | |
| 215 | buf = (float *)seg->buffer->extended_data[ch]; | | |
| 216 | fir_fadd(s, buf, sumout, seg->part_size); | | |
| 217 | | | |
| 218 | memcpy(dst, buf, seg->part_size * sizeof(*dst)); | | |
| 219 | | | |
| 220 | buf = (float *)seg->buffer->extended_data[ch]; | | |
| 221 | memcpy(buf, sumout + seg->part_size, seg->part_size * sizeof(*buf)); | | |
| 222 | | | |
| 223 | seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions; | | |
| 224 | | | |
| 225 | memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); | | |
| 226 | | | |
| 227 | fir_fadd(s, ptr, dst, nb_samples); | | |
| 228 | } | 94 | } |
| | 95 | } |
| 229 | | 96 | |
| 230 | if (s->min_part_size >= 8) { | 97 | #define DEPTH 32 |
| 231 | s->fdsp->vector_fmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 4)); | 98 | #include "afir_template.c" |
| 232 | emms_c(); | | |
| 233 | } else { | | |
| 234 | for (n = 0; n < nb_samples; n++) | | |
| 235 | ptr[n] *= s->wet_gain; | | |
| 236 | } | | |
| 237 | | 99 | |
| 238 | return 0; | 100 | #undef DEPTH |
| 239 | } | 101 | #define DEPTH 64 |
| | 102 | #include "afir_template.c" |
| 240 | | 103 | |
| 241 | static int fir_channel(AVFilterContext *ctx, AVFrame *out, int ch) | 104 | static int fir_channel(AVFilterContext *ctx, AVFrame *out, int ch) |
| 242 | { | 105 | { |
| 243 | AudioFIRContext *s = ctx->priv; | 106 | AudioFIRContext *s = ctx->priv; |
| 244 | | 107 | |
| 245 | for (int offset = 0; offset < out->nb_samples; offset += s->min_part_size) { | 108 | for (int offset = 0; offset < out->nb_samples; offset += s->min_part_size) { |
| 246 | fir_quantum(ctx, out, ch, offset); | 109 | switch (s->format) { |
| | 110 | case AV_SAMPLE_FMT_FLTP: |
| | 111 | fir_quantum_float(ctx, out, ch, offset); |
| | 112 | break; |
| | 113 | case AV_SAMPLE_FMT_DBLP: |
| | 114 | fir_quantum_double(ctx, out, ch, offset); |
| | 115 | break; |
| | 116 | } |
| 247 | } | 117 | } |
| 248 | | 118 | |
| 249 | return 0; | 119 | return 0; |
| @@ -284,144 +154,6 @@ static int fir_frame(AudioFIRContext *s, AVFrame *in, AVFilterLink *outlink) · 34 unmodified lines |
| 284 | return ff_filter_frame(outlink, out); | 154 | return ff_filter_frame(outlink, out); |
| 285 | } | 155 | } |
| 286 | | 156 | |
| 287 | static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color) | | |
| 288 | { | | |
| 289 | const uint8_t *font; | | |
| 290 | int font_height; | | |
| 291 | int i; | | |
| 292 | | | |
| 293 | font = avpriv_cga_font, font_height = 8; | | |
| 294 | | | |
| 295 | for (i = 0; txt[i]; i++) { | | |
| 296 | int char_y, mask; | | |
| 297 | | | |
| 298 | uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4; | | |
| 299 | for (char_y = 0; char_y < font_height; char_y++) { | | |
| 300 | for (mask = 0x80; mask; mask >>= 1) { | | |
| 301 | if (font[txt[i] * font_height + char_y] & mask) | | |
| 302 | AV_WL32(p, color); | | |
| 303 | p += 4; | | |
| 304 | } | | |
| 305 | p += pic->linesize[0] - 8 * 4; | | |
| 306 | } | | |
| 307 | } | | |
| 308 | } | | |
| 309 | | | |
| 310 | static void draw_line(AVFrame *out, int x0, int y0, int x1, int y1, uint32_t color) | | |
| 311 | { | | |
| 312 | int dx = FFABS(x1-x0); | | |
| 313 | int dy = FFABS(y1-y0), sy = y0 < y1 ? 1 : -1; | | |
| 314 | int err = (dx>dy ? dx : -dy) / 2, e2; | | |
| 315 | | | |
| 316 | for (;;) { | | |
| 317 | AV_WL32(out->data[0] + y0 * out->linesize[0] + x0 * 4, color); | | |
| 318 | | | |
| 319 | if (x0 == x1 && y0 == y1) | | |
| 320 | break; | | |
| 321 | | | |
| 322 | e2 = err; | | |
| 323 | | | |
| 324 | if (e2 >-dx) { | | |
| 325 | err -= dy; | | |
| 326 | x0--; | | |
| 327 | } | | |
| 328 | | | |
| 329 | if (e2 < dy) { | | |
| 330 | err += dx; | | |
| 331 | y0 += sy; | | |
| 332 | } | | |
| 333 | } | | |
| 334 | } | | |
| 335 | | | |
| 336 | static void draw_response(AVFilterContext *ctx, AVFrame *out) | | |
| 337 | { | | |
| 338 | AudioFIRContext *s = ctx->priv; | | |
| 339 | float *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN; | | |
| 340 | float min_delay = FLT_MAX, max_delay = FLT_MIN; | | |
| 341 | int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1; | | |
| 342 | char text[32]; | | |
| 343 | int channel, i, x; | | |
| 344 | | | |
| 345 | memset(out->data[0], 0, s->h * out->linesize[0]); | | |
| 346 | | | |
| 347 | phase = av_malloc_array(s->w, sizeof(*phase)); | | |
| 348 | mag = av_malloc_array(s->w, sizeof(*mag)); | | |
| 349 | delay = av_malloc_array(s->w, sizeof(*delay)); | | |
| 350 | if (!mag || !phase || !delay) | | |
| 351 | goto end; | | |
| 352 | | | |
| 353 | channel = av_clip(s->ir_channel, 0, s->ir[s->selir]->ch_layout.nb_channels - 1); | | |
| 354 | for (i = 0; i < s->w; i++) { | | |
| 355 | const float *src = (const float *)s->ir[s->selir]->extended_data[channel]; | | |
| 356 | double w = i * M_PI / (s->w - 1); | | |
| 357 | double div, real_num = 0., imag_num = 0., real = 0., imag = 0.; | | |
| 358 | | | |
| 359 | for (x = 0; x < s->nb_taps; x++) { | | |
| 360 | real += cos(-x * w) * src[x]; | | |
| 361 | imag += sin(-x * w) * src[x]; | | |
| 362 | real_num += cos(-x * w) * src[x] * x; | | |
| 363 | imag_num += sin(-x * w) * src[x] * x; | | |
| 364 | } | | |
| 365 | | | |
| 366 | mag[i] = hypot(real, imag); | | |
| 367 | phase[i] = atan2(imag, real); | | |
| 368 | div = real * real + imag * imag; | | |
| 369 | delay[i] = (real_num * real + imag_num * imag) / div; | | |
| 370 | min = fminf(min, mag[i]); | | |
| 371 | max = fmaxf(max, mag[i]); | | |
| 372 | min_delay = fminf(min_delay, delay[i]); | | |
| 373 | max_delay = fmaxf(max_delay, delay[i]); | | |
| 374 | } | | |
| 375 | | | |
| 376 | for (i = 0; i < s->w; i++) { | | |
| 377 | int ymag = mag[i] / max * (s->h - 1); | | |
| 378 | int ydelay = (delay[i] - min_delay) / (max_delay - min_delay) * (s->h - 1); | | |
| 379 | int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1); | | |
| 380 | | | |
| 381 | ymag = s->h - 1 - av_clip(ymag, 0, s->h - 1); | | |
| 382 | yphase = s->h - 1 - av_clip(yphase, 0, s->h - 1); | | |
| 383 | ydelay = s->h - 1 - av_clip(ydelay, 0, s->h - 1); | | |
| 384 | | | |
| 385 | if (prev_ymag < 0) | | |
| 386 | prev_ymag = ymag; | | |
| 387 | if (prev_yphase < 0) | | |
| 388 | prev_yphase = yphase; | | |
| 389 | if (prev_ydelay < 0) | | |
| 390 | prev_ydelay = ydelay; | | |
| 391 | | | |
| 392 | draw_line(out, i, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF); | | |
| 393 | draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00); | | |
| 394 | draw_line(out, i, ydelay, FFMAX(i - 1, 0), prev_ydelay, 0xFF00FFFF); | | |
| 395 | | | |
| 396 | prev_ymag = ymag; | | |
| 397 | prev_yphase = yphase; | | |
| 398 | prev_ydelay = ydelay; | | |
| 399 | } | | |
| 400 | | | |
| 401 | if (s->w > 400 && s->h > 100) { | | |
| 402 | drawtext(out, 2, 2, "Max Magnitude:", 0xDDDDDDDD); | | |
| 403 | snprintf(text, sizeof(text), "%.2f", max); | | |
| 404 | drawtext(out, 15 * 8 + 2, 2, text, 0xDDDDDDDD); | | |
| 405 | | | |
| 406 | drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD); | | |
| 407 | snprintf(text, sizeof(text), "%.2f", min); | | |
| 408 | drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD); | | |
| 409 | | | |
| 410 | drawtext(out, 2, 22, "Max Delay:", 0xDDDDDDDD); | | |
| 411 | snprintf(text, sizeof(text), "%.2f", max_delay); | | |
| 412 | drawtext(out, 11 * 8 + 2, 22, text, 0xDDDDDDDD); | | |
| 413 | | | |
| 414 | drawtext(out, 2, 32, "Min Delay:", 0xDDDDDDDD); | | |
| 415 | snprintf(text, sizeof(text), "%.2f", min_delay); | | |
| 416 | drawtext(out, 11 * 8 + 2, 32, text, 0xDDDDDDDD); | | |
| 417 | } | | |
| 418 | | | |
| 419 | end: | | |
| 420 | av_free(delay); | | |
| 421 | av_free(phase); | | |
| 422 | av_free(mag); | | |
| 423 | } | | |
| 424 | | | |
| 425 | static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg, | 157 | static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg, |
| 426 | int offset, int nb_partitions, int part_size) | 158 | int offset, int nb_partitions, int part_size) |
| 427 | { | 159 | { |
| @@ -446,9 +178,20 @@ static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg, · 18 unmodified lines |
| 446 | return AVERROR(ENOMEM); | 178 | return AVERROR(ENOMEM); |
| 447 | | 179 | |
| 448 | for (int ch = 0; ch < ctx->inputs[0]->ch_layout.nb_channels && part_size >= 8; ch++) { | 180 | for (int ch = 0; ch < ctx->inputs[0]->ch_layout.nb_channels && part_size >= 8; ch++) { |
| 449 | float scale = 1.f, iscale = 1.f / part_size; | 181 | double dscale = 1.0, idscale = 1.0 / part_size; |
| 450 | av_tx_init(&seg->tx[ch], &seg->tx_fn, AV_TX_FLOAT_RDFT, 0, 2 * part_size, &scale, 0); | 182 | float fscale = 1.f, ifscale = 1.f / part_size; |
| 451 | av_tx_init(&seg->itx[ch], &seg->itx_fn, AV_TX_FLOAT_RDFT, 1, 2 * part_size, &iscale, 0); | 183 | |
| | 184 | switch (s->format) { |
| | 185 | case AV_SAMPLE_FMT_FLTP: |
| | 186 | av_tx_init(&seg->tx[ch], &seg->tx_fn, AV_TX_FLOAT_RDFT, 0, 2 * part_size, &fscale, 0); |
| | 187 | av_tx_init(&seg->itx[ch], &seg->itx_fn, AV_TX_FLOAT_RDFT, 1, 2 * part_size, &ifscale, 0); |
| | 188 | break; |
| | 189 | case AV_SAMPLE_FMT_DBLP: |
| | 190 | av_tx_init(&seg->tx[ch], &seg->tx_fn, AV_TX_DOUBLE_RDFT, 0, 2 * part_size, &dscale, 0); |
| | 191 | av_tx_init(&seg->itx[ch], &seg->itx_fn, AV_TX_DOUBLE_RDFT, 1, 2 * part_size, &idscale, 0); |
| | 192 | break; |
| | 193 | } |
| | 194 | |
| 452 | if (!seg->tx[ch] || !seg->itx[ch]) | 195 | if (!seg->tx[ch] || !seg->itx[ch]) |
| 453 | return AVERROR(ENOMEM); | 196 | return AVERROR(ENOMEM); |
| 454 | } | 197 | } |
| @@ -502,8 +245,7 @@ static void uninit_segment(AVFilterContext *ctx, AudioFIRSegment *seg) · 47 unmodified lines |
| 502 | static int convert_coeffs(AVFilterContext *ctx) | 245 | static int convert_coeffs(AVFilterContext *ctx) |
| 503 | { | 246 | { |
| 504 | AudioFIRContext *s = ctx->priv; | 247 | AudioFIRContext *s = ctx->priv; |
| 505 | int ret, i, ch, n, cur_nb_taps; | 248 | int ret, i, cur_nb_taps; |
| 506 | float power = 0; | | |
| 507 | | 249 | |
| 508 | if (!s->nb_taps) { | 250 | if (!s->nb_taps) { |
| 509 | int part_size, max_part_size; | 251 | int part_size, max_part_size; |
| @@ -546,109 +288,42 @@ static int convert_coeffs(AVFilterContext *ctx) · 36 unmodified lines |
| 546 | return AVERROR_BUG; | 288 | return AVERROR_BUG; |
| 547 | } | 289 | } |
| 548 | | 290 | |
| 549 | if (s->response) | 291 | if (s->response) { |
| 550 | draw_response(ctx, s->video); | 292 | switch (s->format) { |
| | 293 | case AV_SAMPLE_FMT_FLTP: |
| | 294 | draw_response_float(ctx, s->video); |
| | 295 | break; |
| | 296 | case AV_SAMPLE_FMT_DBLP: |
| | 297 | draw_response_double(ctx, s->video); |
| | 298 | break; |
| | 299 | } |
| | 300 | } |
| 551 | | 301 | |
| 552 | s->gain = 1; | 302 | s->gain = 1; |
| 553 | cur_nb_taps = s->ir[s->selir]->nb_samples; | 303 | cur_nb_taps = s->ir[s->selir]->nb_samples; |
| 554 | | 304 | |
| 555 | switch (s->gtype) { | 305 | switch (s->format) { |
| 556 | case -1: | 306 | case AV_SAMPLE_FMT_FLTP: |
| 557 | /* nothing to do */ | 307 | ret = get_power_float(ctx, s, cur_nb_taps); |
| 558 | break; | 308 | break; |
| 559 | case 0: | 309 | case AV_SAMPLE_FMT_DBLP: |
| 560 | for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) { | 310 | ret = get_power_double(ctx, s, cur_nb_taps); |
| 561 | float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch]; | | |
| 562 | | | |
| 563 | for (i = 0; i < cur_nb_taps; i++) | | |
| 564 | power += FFABS(time[i]); | | |
| 565 | } | | |
| 566 | s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power; | | |
| 567 | break; | 311 | break; |
| 568 | case 1: | | |
| 569 | for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) { | | |
| 570 | float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch]; | | |
| 571 | | | |
| 572 | for (i = 0; i < cur_nb_taps; i++) | | |
| 573 | power += time[i]; | | |
| 574 | } | | |
| 575 | s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power; | | |
| 576 | break; | | |
| 577 | case 2: | | |
| 578 | for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) { | | |
| 579 | float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch]; | | |
| 580 | | | |
| 581 | for (i = 0; i < cur_nb_taps; i++) | | |
| 582 | power += time[i] * time[i]; | | |
| 583 | } | | |
| 584 | s->gain = sqrtf(ch / power); | | |
| 585 | break; | | |
| 586 | default: | | |
| 587 | return AVERROR_BUG; | | |
| 588 | } | 312 | } |
| 589 | | 313 | |
| 590 | s->gain = FFMIN(s->gain * s->ir_gain, 1.f); | 314 | if (ret < 0) |
| 591 | av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain); | 315 | return ret; |
| 592 | for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) { | | |
| 593 | float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch]; | | |
| 594 | | | |
| 595 | s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(cur_nb_taps, 4)); | | |
| 596 | } | | |
| 597 | | 316 | |
| 598 | av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", cur_nb_taps); | 317 | av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", cur_nb_taps); |
| 599 | av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments); | 318 | av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments); |
| 600 | | 319 | |
| 601 | for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) { | 320 | switch (s->format) { |
| 602 | float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch]; | 321 | case AV_SAMPLE_FMT_FLTP: |
| 603 | int toffset = 0; | 322 | convert_channels_float(ctx, s); |
| 604 | | 323 | break; |
| 605 | for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++) | 324 | case AV_SAMPLE_FMT_DBLP: |
| 606 | time[i] = 0; | 325 | convert_channels_double(ctx, s); |
| 607 | | 326 | break; |
| 608 | av_log(ctx, AV_LOG_DEBUG, "channel: %d\n", ch); | | |
| 609 | | | |
| 610 | for (int segment = 0; segment < s->nb_segments; segment++) { | | |
| 611 | AudioFIRSegment *seg = &s->seg[segment]; | | |
| 612 | float *blockin = (float *)seg->blockin->extended_data[ch]; | | |
| 613 | float *blockout = (float *)seg->blockout->extended_data[ch]; | | |
| 614 | AVComplexFloat *coeff = (AVComplexFloat *)seg->coeff->extended_data[ch]; | | |
| 615 | | | |
| 616 | av_log(ctx, AV_LOG_DEBUG, "segment: %d\n", segment); | | |
| 617 | | | |
| 618 | for (i = 0; i < seg->nb_partitions; i++) { | | |
| 619 | const int coffset = i * seg->coeff_size; | | |
| 620 | const int remaining = s->nb_taps - toffset; | | |
| 621 | const int size = remaining >= seg->part_size ? seg->part_size : remaining; | | |
| 622 | | | |
| 623 | if (size < 8) { | | |
| 624 | for (n = 0; n < size; n++) | | |
| 625 | coeff[coffset + n].re = time[toffset + n]; | | |
| 626 | | | |
| 627 | toffset += size; | | |
| 628 | continue; | | |
| 629 | } | | |
| 630 | | | |
| 631 | memset(blockin, 0, sizeof(*blockin) * seg->fft_length); | | |
| 632 | memcpy(blockin, time + toffset, size * sizeof(*blockin)); | | |
| 633 | | | |
| 634 | seg->tx_fn(seg->tx[0], blockout, blockin, sizeof(float)); | | |
| 635 | | | |
| 636 | for (n = 0; n < seg->part_size + 1; n++) { | | |
| 637 | coeff[coffset + n].re = blockout[2 * n]; | | |
| 638 | coeff[coffset + n].im = blockout[2 * n + 1]; | | |
| 639 | } | | |
| 640 | | | |
| 641 | toffset += size; | | |
| 642 | } | | |
| 643 | | | |
| 644 | av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", seg->nb_partitions); | | |
| 645 | av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", seg->part_size); | | |
| 646 | av_log(ctx, AV_LOG_DEBUG, "block size: %d\n", seg->block_size); | | |
| 647 | av_log(ctx, AV_LOG_DEBUG, "fft_length: %d\n", seg->fft_length); | | |
| 648 | av_log(ctx, AV_LOG_DEBUG, "coeff_size: %d\n", seg->coeff_size); | | |
| 649 | av_log(ctx, AV_LOG_DEBUG, "input_size: %d\n", seg->input_size); | | |
| 650 | av_log(ctx, AV_LOG_DEBUG, "input_offset: %d\n", seg->input_offset); | | |
| 651 | } | | |
| 652 | } | 327 | } |
| 653 | | 328 | |
| 654 | s->have_coeffs = 1; | 329 | s->have_coeffs = 1; |
| @@ -762,9 +437,10 @@ static int activate(AVFilterContext *ctx) · 107 unmodified lines |
| 762 | static int query_formats(AVFilterContext *ctx) | 437 | static int query_formats(AVFilterContext *ctx) |
| 763 | { | 438 | { |
| 764 | AudioFIRContext *s = ctx->priv; | 439 | AudioFIRContext *s = ctx->priv; |
| 765 | static const enum AVSampleFormat sample_fmts[] = { | 440 | static const enum AVSampleFormat sample_fmts[3][3] = { |
| 766 | AV_SAMPLE_FMT_FLTP, | 441 | { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, |
| 767 | AV_SAMPLE_FMT_NONE | 442 | { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, |
| | 443 | { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, |
| 768 | }; | 444 | }; |
| 769 | static const enum AVPixelFormat pix_fmts[] = { | 445 | static const enum AVPixelFormat pix_fmts[] = { |
| 770 | AV_PIX_FMT_RGB0, | 446 | AV_PIX_FMT_RGB0, |
| @@ -801,7 +477,7 @@ static int query_formats(AVFilterContext *ctx) · 30 unmodified lines |
| 801 | } | 477 | } |
| 802 | } | 478 | } |
| 803 | | 479 | |
| 804 | if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts)) < 0) | 480 | if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) |
| 805 | return ret; | 481 | return ret; |
| 806 | | 482 | |
| 807 | return ff_set_common_all_samplerates(ctx); | 483 | return ff_set_common_all_samplerates(ctx); |
| @@ -827,6 +503,7 @@ FF_ENABLE_DEPRECATION_WARNINGS · 19 unmodified lines |
| 827 | | 503 | |
| 828 | s->nb_channels = outlink->ch_layout.nb_channels; | 504 | s->nb_channels = outlink->ch_layout.nb_channels; |
| 829 | s->nb_coef_channels = ctx->inputs[1 + s->selir]->ch_layout.nb_channels; | 505 | s->nb_coef_channels = ctx->inputs[1 + s->selir]->ch_layout.nb_channels; |
| | 506 | s->format = outlink->format; |
| 830 | | 507 | |
| 831 | return 0; | 508 | return 0; |
| 832 | } | 509 | } |
| @@ -977,6 +654,10 @@ static const AVOption afir_options[] = { · 144 unmodified lines |
| 977 | { "maxp", "set max partition size", OFFSET(maxp), AV_OPT_TYPE_INT, {.i64=8192}, 8, 32768, AF }, | 654 | { "maxp", "set max partition size", OFFSET(maxp), AV_OPT_TYPE_INT, {.i64=8192}, 8, 32768, AF }, |
| 978 | { "nbirs", "set number of input IRs",OFFSET(nb_irs),AV_OPT_TYPE_INT, {.i64=1}, 1, 32, AF }, | 655 | { "nbirs", "set number of input IRs",OFFSET(nb_irs),AV_OPT_TYPE_INT, {.i64=1}, 1, 32, AF }, |
| 979 | { "ir", "select IR", OFFSET(selir), AV_OPT_TYPE_INT, {.i64=0}, 0, 31, AFR }, | 656 | { "ir", "select IR", OFFSET(selir), AV_OPT_TYPE_INT, {.i64=0}, 0, 31, AFR }, |
| | 657 | { "precision", "set processing precision", OFFSET(precision), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, AF, "precision" }, |
| | 658 | { "auto", "set auto processing precision", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "precision" }, |
| | 659 | { "float", "set single-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision" }, |
| | 660 | { "double","set double-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision" }, |
| 980 | { NULL } | 661 | { NULL } |
| 981 | }; | 662 | }; |
| 982 | | 663 | |