FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_arnndn.c
Date: 2026-10-29 07:45:57
Exec Total Coverage
Lines: 0 771 0.0%
Functions: 0 41 0.0%
Branches: 0 712 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2018 Gregor Richards
3 * Copyright (c) 2017 Mozilla
4 * Copyright (c) 2005-2009 Xiph.Org Foundation
5 * Copyright (c) 2007-2008 CSIRO
6 * Copyright (c) 2008-2011 Octasic Inc.
7 * Copyright (c) Jean-Marc Valin
8 * Copyright (c) 2019 Paul B Mahol
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "libavutil/avassert.h"
35 #include "libavutil/file_open.h"
36 #include "libavutil/float_dsp.h"
37 #include "libavutil/mem.h"
38 #include "libavutil/mem_internal.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/tx.h"
41 #include "avfilter.h"
42 #include "audio.h"
43 #include "filters.h"
44 #include "formats.h"
45
46 #define FRAME_SIZE_SHIFT 2
47 #define FRAME_SIZE (120<<FRAME_SIZE_SHIFT)
48 #define WINDOW_SIZE (2*FRAME_SIZE)
49 #define FREQ_SIZE (FRAME_SIZE + 1)
50
51 #define PITCH_MIN_PERIOD 60
52 #define PITCH_MAX_PERIOD 768
53 #define PITCH_FRAME_SIZE 960
54 #define PITCH_BUF_SIZE (PITCH_MAX_PERIOD+PITCH_FRAME_SIZE)
55
56 #define SQUARE(x) ((x)*(x))
57
58 #define NB_BANDS 22
59
60 #define CEPS_MEM 8
61 #define NB_DELTA_CEPS 6
62
63 #define NB_FEATURES (NB_BANDS+3*NB_DELTA_CEPS+2)
64
65 #define WEIGHTS_SCALE (1.f/256)
66
67 #define MAX_NEURONS 128
68
69 #define ACTIVATION_TANH 0
70 #define ACTIVATION_SIGMOID 1
71 #define ACTIVATION_RELU 2
72
73 #define Q15ONE 1.0f
74
75 typedef struct DenseLayer {
76 const float *bias;
77 const float *input_weights;
78 int nb_inputs;
79 int nb_neurons;
80 int activation;
81 } DenseLayer;
82
83 typedef struct GRULayer {
84 const float *bias;
85 const float *input_weights;
86 const float *recurrent_weights;
87 int nb_inputs;
88 int nb_neurons;
89 int activation;
90 } GRULayer;
91
92 typedef struct RNNModel {
93 int input_dense_size;
94 const DenseLayer *input_dense;
95
96 int vad_gru_size;
97 const GRULayer *vad_gru;
98
99 int noise_gru_size;
100 const GRULayer *noise_gru;
101
102 int denoise_gru_size;
103 const GRULayer *denoise_gru;
104
105 int denoise_output_size;
106 const DenseLayer *denoise_output;
107
108 int vad_output_size;
109 const DenseLayer *vad_output;
110 } RNNModel;
111
112 typedef struct RNNState {
113 float *vad_gru_state;
114 float *noise_gru_state;
115 float *denoise_gru_state;
116 RNNModel *model;
117 } RNNState;
118
119 typedef struct DenoiseState {
120 float analysis_mem[FRAME_SIZE];
121 float cepstral_mem[CEPS_MEM][NB_BANDS];
122 int memid;
123 DECLARE_ALIGNED(32, float, synthesis_mem)[FRAME_SIZE];
124 float pitch_buf[PITCH_BUF_SIZE];
125 float pitch_enh_buf[PITCH_BUF_SIZE];
126 float last_gain;
127 int last_period;
128 float mem_hp_x[2];
129 float lastg[NB_BANDS];
130 float history[FRAME_SIZE];
131 RNNState rnn[2];
132 AVTXContext *tx, *txi;
133 av_tx_fn tx_fn, txi_fn;
134 } DenoiseState;
135
136 typedef struct AudioRNNContext {
137 const AVClass *class;
138
139 char *model_name;
140 float mix;
141
142 int channels;
143 DenoiseState *st;
144
145 DECLARE_ALIGNED(32, float, window)[WINDOW_SIZE];
146 DECLARE_ALIGNED(32, float, dct_table)[FFALIGN(NB_BANDS, 4)][FFALIGN(NB_BANDS, 4)];
147
148 RNNModel *model[2];
149
150 AVFloatDSPContext *fdsp;
151 } AudioRNNContext;
152
153 #define F_ACTIVATION_TANH 0
154 #define F_ACTIVATION_SIGMOID 1
155 #define F_ACTIVATION_RELU 2
156
157 ✗ static void rnnoise_model_free(RNNModel *model)
158 {
159 #define FREE_MAYBE(ptr) do { if (ptr) free(ptr); } while (0)
160 #define FREE_DENSE(name) do { \
161 if (model->name) { \
162 av_free((void *) model->name->input_weights); \
163 av_free((void *) model->name->bias); \
164 av_free((void *) model->name); \
165 } \
166 } while (0)
167 #define FREE_GRU(name) do { \
168 if (model->name) { \
169 av_free((void *) model->name->input_weights); \
170 av_free((void *) model->name->recurrent_weights); \
171 av_free((void *) model->name->bias); \
172 av_free((void *) model->name); \
173 } \
174 } while (0)
175
176 ✗ if (!model)
177 ✗ return;
178 ✗ FREE_DENSE(input_dense);
179 ✗ FREE_GRU(vad_gru);
180 ✗ FREE_GRU(noise_gru);
181 ✗ FREE_GRU(denoise_gru);
182 ✗ FREE_DENSE(denoise_output);
183 ✗ FREE_DENSE(vad_output);
184 ✗ av_free(model);
185 }
186
187 ✗ static int rnnoise_model_from_file(FILE *f, RNNModel **rnn)
188 {
189 ✗ RNNModel *ret = NULL;
190 DenseLayer *input_dense;
191 GRULayer *vad_gru;
192 GRULayer *noise_gru;
193 GRULayer *denoise_gru;
194 DenseLayer *denoise_output;
195 DenseLayer *vad_output;
196 int in;
197
198 ✗ if (fscanf(f, "rnnoise-nu model file version %d\n", &in) != 1 || in != 1)
199 ✗ return AVERROR_INVALIDDATA;
200
201 ✗ ret = av_calloc(1, sizeof(RNNModel));
202 ✗ if (!ret)
203 ✗ return AVERROR(ENOMEM);
204
205 #define ALLOC_LAYER(type, name) \
206 name = av_calloc(1, sizeof(type)); \
207 if (!name) { \
208 rnnoise_model_free(ret); \
209 return AVERROR(ENOMEM); \
210 } \
211 ret->name = name
212
213 ✗ ALLOC_LAYER(DenseLayer, input_dense);
214 ✗ ALLOC_LAYER(GRULayer, vad_gru);
215 ✗ ALLOC_LAYER(GRULayer, noise_gru);
216 ✗ ALLOC_LAYER(GRULayer, denoise_gru);
217 ✗ ALLOC_LAYER(DenseLayer, denoise_output);
218 ✗ ALLOC_LAYER(DenseLayer, vad_output);
219
220 #define INPUT_VAL(name, min) do { \
221 if (fscanf(f, "%d", &in) != 1 || in < (min) || in > 128) { \
222 rnnoise_model_free(ret); \
223 return AVERROR(EINVAL); \
224 } \
225 name = in; \
226 } while (0)
227
228 #define INPUT_ACTIVATION(name) do { \
229 int activation; \
230 INPUT_VAL(activation, 0); \
231 switch (activation) { \
232 case F_ACTIVATION_SIGMOID: \
233 name = ACTIVATION_SIGMOID; \
234 break; \
235 case F_ACTIVATION_RELU: \
236 name = ACTIVATION_RELU; \
237 break; \
238 default: \
239 name = ACTIVATION_TANH; \
240 } \
241 } while (0)
242
243 #define INPUT_ARRAY(name, len) do { \
244 float *values = av_calloc((len), sizeof(float)); \
245 if (!values) { \
246 rnnoise_model_free(ret); \
247 return AVERROR(ENOMEM); \
248 } \
249 name = values; \
250 for (int i = 0; i < (len); i++) { \
251 if (fscanf(f, "%d", &in) != 1) { \
252 rnnoise_model_free(ret); \
253 return AVERROR(EINVAL); \
254 } \
255 values[i] = in; \
256 } \
257 } while (0)
258
259 #define INPUT_ARRAY3(name, len0, len1, len2) do { \
260 float *values = av_calloc(FFALIGN((len0), 4) * FFALIGN((len1), 4) * (len2), sizeof(float)); \
261 if (!values) { \
262 rnnoise_model_free(ret); \
263 return AVERROR(ENOMEM); \
264 } \
265 name = values; \
266 for (int k = 0; k < (len0); k++) { \
267 for (int i = 0; i < (len2); i++) { \
268 for (int j = 0; j < (len1); j++) { \
269 if (fscanf(f, "%d", &in) != 1) { \
270 rnnoise_model_free(ret); \
271 return AVERROR(EINVAL); \
272 } \
273 values[j * (len2) * FFALIGN((len0), 4) + i * FFALIGN((len0), 4) + k] = in; \
274 } \
275 } \
276 } \
277 } while (0)
278
279 #define NEW_LINE() do { \
280 int c; \
281 while ((c = fgetc(f)) != EOF) { \
282 if (c == '\n') \
283 break; \
284 } \
285 } while (0)
286
287 #define INPUT_DENSE(name) do { \
288 INPUT_VAL(name->nb_inputs, 1); \
289 INPUT_VAL(name->nb_neurons, 1); \
290 ret->name ## _size = name->nb_neurons; \
291 INPUT_ACTIVATION(name->activation); \
292 NEW_LINE(); \
293 INPUT_ARRAY(name->input_weights, name->nb_inputs * name->nb_neurons); \
294 NEW_LINE(); \
295 INPUT_ARRAY(name->bias, name->nb_neurons); \
296 NEW_LINE(); \
297 } while (0)
298
299 #define INPUT_GRU(name) do { \
300 INPUT_VAL(name->nb_inputs, 1); \
301 INPUT_VAL(name->nb_neurons, 1); \
302 ret->name ## _size = name->nb_neurons; \
303 INPUT_ACTIVATION(name->activation); \
304 NEW_LINE(); \
305 INPUT_ARRAY3(name->input_weights, name->nb_inputs, name->nb_neurons, 3); \
306 NEW_LINE(); \
307 INPUT_ARRAY3(name->recurrent_weights, name->nb_neurons, name->nb_neurons, 3); \
308 NEW_LINE(); \
309 INPUT_ARRAY(name->bias, name->nb_neurons * 3); \
310 NEW_LINE(); \
311 } while (0)
312
313 ✗ INPUT_DENSE(input_dense);
314 ✗ INPUT_GRU(vad_gru);
315 ✗ INPUT_GRU(noise_gru);
316 ✗ INPUT_GRU(denoise_gru);
317 ✗ INPUT_DENSE(denoise_output);
318 ✗ INPUT_DENSE(vad_output);
319
320 ✗ if (input_dense->nb_inputs != NB_FEATURES ||
321 ✗ vad_gru->nb_inputs != input_dense->nb_neurons ||
322 ✗ noise_gru->nb_inputs != input_dense->nb_neurons + vad_gru->nb_neurons + NB_FEATURES ||
323 ✗ denoise_gru->nb_inputs != vad_gru->nb_neurons + noise_gru->nb_neurons + NB_FEATURES ||
324 ✗ denoise_output->nb_inputs != denoise_gru->nb_neurons ||
325 ✗ denoise_output->nb_neurons != NB_BANDS ||
326 ✗ vad_output->nb_inputs != vad_gru->nb_neurons ||
327 ✗ vad_output->nb_neurons != 1) {
328 ✗ rnnoise_model_free(ret);
329 ✗ return AVERROR(EINVAL);
330 }
331
332 ✗ *rnn = ret;
333
334 ✗ return 0;
335 }
336
337 ✗ static int query_formats(const AVFilterContext *ctx,
338 AVFilterFormatsConfig **cfg_in,
339 AVFilterFormatsConfig **cfg_out)
340 {
341 static const enum AVSampleFormat sample_fmts[] = {
342 AV_SAMPLE_FMT_FLTP,
343 AV_SAMPLE_FMT_NONE
344 };
345 ✗ int ret, sample_rates[] = { 48000, -1 };
346
347 ✗ ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts);
348 ✗ if (ret < 0)
349 ✗ return ret;
350
351 ✗ return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates);
352 }
353
354 ✗ static int config_input(AVFilterLink *inlink)
355 {
356 ✗ AVFilterContext *ctx = inlink->dst;
357 ✗ AudioRNNContext *s = ctx->priv;
358 ✗ int ret = 0;
359
360 ✗ s->channels = inlink->ch_layout.nb_channels;
361
362 ✗ if (!s->st)
363 ✗ s->st = av_calloc(s->channels, sizeof(DenoiseState));
364 ✗ if (!s->st)
365 ✗ return AVERROR(ENOMEM);
366
367 ✗ for (int i = 0; i < s->channels; i++) {
368 ✗ DenoiseState *st = &s->st[i];
369
370 ✗ st->rnn[0].model = s->model[0];
371 ✗ st->rnn[0].vad_gru_state = av_calloc(FFALIGN(s->model[0]->vad_gru_size, 16), sizeof(float));
372 ✗ st->rnn[0].noise_gru_state = av_calloc(FFALIGN(s->model[0]->noise_gru_size, 16), sizeof(float));
373 ✗ st->rnn[0].denoise_gru_state = av_calloc(FFALIGN(s->model[0]->denoise_gru_size, 16), sizeof(float));
374 ✗ if (!st->rnn[0].vad_gru_state ||
375 ✗ !st->rnn[0].noise_gru_state ||
376 ✗ !st->rnn[0].denoise_gru_state)
377 ✗ return AVERROR(ENOMEM);
378 }
379
380 ✗ for (int i = 0; i < s->channels; i++) {
381 ✗ DenoiseState *st = &s->st[i];
382 ✗ float scale = 1.f;
383
384 ✗ if (!st->tx)
385 ✗ ret = av_tx_init(&st->tx, &st->tx_fn, AV_TX_FLOAT_FFT, 0, WINDOW_SIZE, &scale, 0);
386 ✗ if (ret < 0)
387 ✗ return ret;
388
389 ✗ if (!st->txi)
390 ✗ ret = av_tx_init(&st->txi, &st->txi_fn, AV_TX_FLOAT_FFT, 1, WINDOW_SIZE, &scale, 0);
391 ✗ if (ret < 0)
392 ✗ return ret;
393 }
394
395 ✗ return ret;
396 }
397
398 ✗ static void biquad(float *y, float mem[2], const float *x,
399 const float *b, const float *a, int N)
400 {
401 ✗ for (int i = 0; i < N; i++) {
402 float xi, yi;
403
404 ✗ xi = x[i];
405 ✗ yi = x[i] + mem[0];
406 ✗ mem[0] = mem[1] + (b[0]*xi - a[0]*yi);
407 ✗ mem[1] = (b[1]*xi - a[1]*yi);
408 ✗ y[i] = yi;
409 }
410 ✗ }
411
412 #define RNN_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
413 #define RNN_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
414 #define RNN_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
415
416 ✗ static void forward_transform(DenoiseState *st, AVComplexFloat *out, const float *in)
417 {
418 AVComplexFloat x[WINDOW_SIZE];
419 AVComplexFloat y[WINDOW_SIZE];
420
421 ✗ for (int i = 0; i < WINDOW_SIZE; i++) {
422 ✗ x[i].re = in[i];
423 ✗ x[i].im = 0;
424 }
425
426 ✗ st->tx_fn(st->tx, y, x, sizeof(AVComplexFloat));
427
428 ✗ RNN_COPY(out, y, FREQ_SIZE);
429 ✗ }
430
431 ✗ static void inverse_transform(DenoiseState *st, float *out, const AVComplexFloat *in)
432 {
433 AVComplexFloat x[WINDOW_SIZE];
434 AVComplexFloat y[WINDOW_SIZE];
435
436 ✗ RNN_COPY(x, in, FREQ_SIZE);
437
438 ✗ for (int i = FREQ_SIZE; i < WINDOW_SIZE; i++) {
439 ✗ x[i].re = x[WINDOW_SIZE - i].re;
440 ✗ x[i].im = -x[WINDOW_SIZE - i].im;
441 }
442
443 ✗ st->txi_fn(st->txi, y, x, sizeof(AVComplexFloat));
444
445 ✗ for (int i = 0; i < WINDOW_SIZE; i++)
446 ✗ out[i] = y[i].re / WINDOW_SIZE;
447 ✗ }
448
449 static const uint8_t eband5ms[] = {
450 /*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 20k*/
451 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
452 };
453
454 ✗ static void compute_band_energy(float *bandE, const AVComplexFloat *X)
455 {
456 ✗ float sum[NB_BANDS] = {0};
457
458 ✗ for (int i = 0; i < NB_BANDS - 1; i++) {
459 int band_size;
460
461 ✗ band_size = (eband5ms[i + 1] - eband5ms[i]) << FRAME_SIZE_SHIFT;
462 ✗ for (int j = 0; j < band_size; j++) {
463 ✗ float tmp, frac = (float)j / band_size;
464
465 ✗ tmp = SQUARE(X[(eband5ms[i] << FRAME_SIZE_SHIFT) + j].re);
466 ✗ tmp += SQUARE(X[(eband5ms[i] << FRAME_SIZE_SHIFT) + j].im);
467 ✗ sum[i] += (1.f - frac) * tmp;
468 ✗ sum[i + 1] += frac * tmp;
469 }
470 }
471
472 ✗ sum[0] *= 2;
473 ✗ sum[NB_BANDS - 1] *= 2;
474
475 ✗ for (int i = 0; i < NB_BANDS; i++)
476 ✗ bandE[i] = sum[i];
477 ✗ }
478
479 ✗ static void compute_band_corr(float *bandE, const AVComplexFloat *X, const AVComplexFloat *P)
480 {
481 ✗ float sum[NB_BANDS] = { 0 };
482
483 ✗ for (int i = 0; i < NB_BANDS - 1; i++) {
484 int band_size;
485
486 ✗ band_size = (eband5ms[i + 1] - eband5ms[i]) << FRAME_SIZE_SHIFT;
487 ✗ for (int j = 0; j < band_size; j++) {
488 ✗ float tmp, frac = (float)j / band_size;
489
490 ✗ tmp = X[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].re * P[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].re;
491 ✗ tmp += X[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].im * P[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].im;
492 ✗ sum[i] += (1 - frac) * tmp;
493 ✗ sum[i + 1] += frac * tmp;
494 }
495 }
496
497 ✗ sum[0] *= 2;
498 ✗ sum[NB_BANDS-1] *= 2;
499
500 ✗ for (int i = 0; i < NB_BANDS; i++)
501 ✗ bandE[i] = sum[i];
502 ✗ }
503
504 ✗ static void frame_analysis(AudioRNNContext *s, DenoiseState *st, AVComplexFloat *X, float *Ex, const float *in)
505 {
506 ✗ LOCAL_ALIGNED_32(float, x, [WINDOW_SIZE]);
507
508 ✗ RNN_COPY(x, st->analysis_mem, FRAME_SIZE);
509 ✗ RNN_COPY(x + FRAME_SIZE, in, FRAME_SIZE);
510 ✗ RNN_COPY(st->analysis_mem, in, FRAME_SIZE);
511 ✗ s->fdsp->vector_fmul(x, x, s->window, WINDOW_SIZE);
512 ✗ forward_transform(st, X, x);
513 ✗ compute_band_energy(Ex, X);
514 ✗ }
515
516 ✗ static void frame_synthesis(AudioRNNContext *s, DenoiseState *st, float *out, const AVComplexFloat *y)
517 {
518 ✗ LOCAL_ALIGNED_32(float, x, [WINDOW_SIZE]);
519 ✗ const float *src = st->history;
520 ✗ const float mix = s->mix;
521 ✗ const float imix = 1.f - FFMAX(mix, 0.f);
522
523 ✗ inverse_transform(st, x, y);
524 ✗ s->fdsp->vector_fmul(x, x, s->window, WINDOW_SIZE);
525 ✗ s->fdsp->vector_fmac_scalar(x, st->synthesis_mem, 1.f, FRAME_SIZE);
526 ✗ RNN_COPY(out, x, FRAME_SIZE);
527 ✗ RNN_COPY(st->synthesis_mem, &x[FRAME_SIZE], FRAME_SIZE);
528
529 ✗ for (int n = 0; n < FRAME_SIZE; n++)
530 ✗ out[n] = out[n] * mix + src[n] * imix;
531 ✗ }
532
533 ✗ static inline void xcorr_kernel(const float *x, const float *y, float sum[4], int len)
534 {
535 ✗ float y_0, y_1, y_2, y_3 = 0;
536 int j;
537
538 ✗ y_0 = *y++;
539 ✗ y_1 = *y++;
540 ✗ y_2 = *y++;
541
542 ✗ for (j = 0; j < len - 3; j += 4) {
543 float tmp;
544
545 ✗ tmp = *x++;
546 ✗ y_3 = *y++;
547 ✗ sum[0] += tmp * y_0;
548 ✗ sum[1] += tmp * y_1;
549 ✗ sum[2] += tmp * y_2;
550 ✗ sum[3] += tmp * y_3;
551 ✗ tmp = *x++;
552 ✗ y_0 = *y++;
553 ✗ sum[0] += tmp * y_1;
554 ✗ sum[1] += tmp * y_2;
555 ✗ sum[2] += tmp * y_3;
556 ✗ sum[3] += tmp * y_0;
557 ✗ tmp = *x++;
558 ✗ y_1 = *y++;
559 ✗ sum[0] += tmp * y_2;
560 ✗ sum[1] += tmp * y_3;
561 ✗ sum[2] += tmp * y_0;
562 ✗ sum[3] += tmp * y_1;
563 ✗ tmp = *x++;
564 ✗ y_2 = *y++;
565 ✗ sum[0] += tmp * y_3;
566 ✗ sum[1] += tmp * y_0;
567 ✗ sum[2] += tmp * y_1;
568 ✗ sum[3] += tmp * y_2;
569 }
570
571 ✗ if (j++ < len) {
572 ✗ float tmp = *x++;
573
574 ✗ y_3 = *y++;
575 ✗ sum[0] += tmp * y_0;
576 ✗ sum[1] += tmp * y_1;
577 ✗ sum[2] += tmp * y_2;
578 ✗ sum[3] += tmp * y_3;
579 }
580
581 ✗ if (j++ < len) {
582 ✗ float tmp=*x++;
583
584 ✗ y_0 = *y++;
585 ✗ sum[0] += tmp * y_1;
586 ✗ sum[1] += tmp * y_2;
587 ✗ sum[2] += tmp * y_3;
588 ✗ sum[3] += tmp * y_0;
589 }
590
591 ✗ if (j < len) {
592 ✗ float tmp=*x++;
593
594 ✗ y_1 = *y++;
595 ✗ sum[0] += tmp * y_2;
596 ✗ sum[1] += tmp * y_3;
597 ✗ sum[2] += tmp * y_0;
598 ✗ sum[3] += tmp * y_1;
599 }
600 ✗ }
601
602 ✗ static inline float celt_inner_prod(const float *x,
603 const float *y, int N)
604 {
605 ✗ float xy = 0.f;
606
607 ✗ for (int i = 0; i < N; i++)
608 ✗ xy += x[i] * y[i];
609
610 ✗ return xy;
611 }
612
613 ✗ static void celt_pitch_xcorr(const float *x, const float *y,
614 float *xcorr, int len, int max_pitch)
615 {
616 int i;
617
618 ✗ for (i = 0; i < max_pitch - 3; i += 4) {
619 ✗ float sum[4] = { 0, 0, 0, 0};
620
621 ✗ xcorr_kernel(x, y + i, sum, len);
622
623 ✗ xcorr[i] = sum[0];
624 ✗ xcorr[i + 1] = sum[1];
625 ✗ xcorr[i + 2] = sum[2];
626 ✗ xcorr[i + 3] = sum[3];
627 }
628 /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
629 ✗ for (; i < max_pitch; i++) {
630 ✗ xcorr[i] = celt_inner_prod(x, y + i, len);
631 }
632 ✗ }
633
634 ✗ static int celt_autocorr(const float *x, /* in: [0...n-1] samples x */
635 float *ac, /* out: [0...lag-1] ac values */
636 const float *window,
637 int overlap,
638 int lag,
639 int n)
640 {
641 ✗ int fastN = n - lag;
642 int shift;
643 const float *xptr;
644 float xx[PITCH_BUF_SIZE>>1];
645
646 ✗ if (overlap == 0) {
647 ✗ xptr = x;
648 } else {
649 ✗ for (int i = 0; i < n; i++)
650 ✗ xx[i] = x[i];
651 ✗ for (int i = 0; i < overlap; i++) {
652 ✗ xx[i] = x[i] * window[i];
653 ✗ xx[n-i-1] = x[n-i-1] * window[i];
654 }
655 ✗ xptr = xx;
656 }
657
658 ✗ shift = 0;
659 ✗ celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1);
660
661 ✗ for (int k = 0; k <= lag; k++) {
662 ✗ float d = 0.f;
663
664 ✗ for (int i = k + fastN; i < n; i++)
665 ✗ d += xptr[i] * xptr[i-k];
666 ✗ ac[k] += d;
667 }
668
669 ✗ return shift;
670 }
671
672 ✗ static void celt_lpc(float *lpc, /* out: [0...p-1] LPC coefficients */
673 const float *ac, /* in: [0...p] autocorrelation values */
674 int p)
675 {
676 ✗ float r, error = ac[0];
677
678 ✗ RNN_CLEAR(lpc, p);
679 ✗ if (ac[0] != 0) {
680 ✗ for (int i = 0; i < p; i++) {
681 /* Sum up this iteration's reflection coefficient */
682 ✗ float rr = 0;
683 ✗ for (int j = 0; j < i; j++)
684 ✗ rr += (lpc[j] * ac[i - j]);
685 ✗ rr += ac[i + 1];
686 ✗ r = -rr/error;
687 /* Update LPC coefficients and total error */
688 ✗ lpc[i] = r;
689 ✗ for (int j = 0; j < (i + 1) >> 1; j++) {
690 float tmp1, tmp2;
691 ✗ tmp1 = lpc[j];
692 ✗ tmp2 = lpc[i-1-j];
693 ✗ lpc[j] = tmp1 + (r*tmp2);
694 ✗ lpc[i-1-j] = tmp2 + (r*tmp1);
695 }
696
697 ✗ error = error - (r * r *error);
698 /* Bail out once we get 30 dB gain */
699 ✗ if (error < .001f * ac[0])
700 ✗ break;
701 }
702 }
703 ✗ }
704
705 ✗ static void celt_fir5(const float *x,
706 const float *num,
707 float *y,
708 int N,
709 float *mem)
710 {
711 float num0, num1, num2, num3, num4;
712 float mem0, mem1, mem2, mem3, mem4;
713
714 ✗ num0 = num[0];
715 ✗ num1 = num[1];
716 ✗ num2 = num[2];
717 ✗ num3 = num[3];
718 ✗ num4 = num[4];
719 ✗ mem0 = mem[0];
720 ✗ mem1 = mem[1];
721 ✗ mem2 = mem[2];
722 ✗ mem3 = mem[3];
723 ✗ mem4 = mem[4];
724
725 ✗ for (int i = 0; i < N; i++) {
726 ✗ float sum = x[i];
727
728 ✗ sum += (num0*mem0);
729 ✗ sum += (num1*mem1);
730 ✗ sum += (num2*mem2);
731 ✗ sum += (num3*mem3);
732 ✗ sum += (num4*mem4);
733 ✗ mem4 = mem3;
734 ✗ mem3 = mem2;
735 ✗ mem2 = mem1;
736 ✗ mem1 = mem0;
737 ✗ mem0 = x[i];
738 ✗ y[i] = sum;
739 }
740
741 ✗ mem[0] = mem0;
742 ✗ mem[1] = mem1;
743 ✗ mem[2] = mem2;
744 ✗ mem[3] = mem3;
745 ✗ mem[4] = mem4;
746 ✗ }
747
748 ✗ static void pitch_downsample(float *x[], float *x_lp,
749 int len, int C)
750 {
751 float ac[5];
752 ✗ float tmp=Q15ONE;
753 ✗ float lpc[4], mem[5]={0,0,0,0,0};
754 float lpc2[5];
755 ✗ float c1 = .8f;
756
757 ✗ for (int i = 1; i < len >> 1; i++)
758 ✗ x_lp[i] = .5f * (.5f * (x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]);
759 ✗ x_lp[0] = .5f * (.5f * (x[0][1])+x[0][0]);
760 ✗ if (C==2) {
761 ✗ for (int i = 1; i < len >> 1; i++)
762 ✗ x_lp[i] += (.5f * (.5f * (x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]));
763 ✗ x_lp[0] += .5f * (.5f * (x[1][1])+x[1][0]);
764 }
765
766 ✗ celt_autocorr(x_lp, ac, NULL, 0, 4, len>>1);
767
768 /* Noise floor -40 dB */
769 ✗ ac[0] *= 1.0001f;
770 /* Lag windowing */
771 ✗ for (int i = 1; i <= 4; i++) {
772 /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
773 ✗ ac[i] -= ac[i]*(.008f*i)*(.008f*i);
774 }
775
776 ✗ celt_lpc(lpc, ac, 4);
777 ✗ for (int i = 0; i < 4; i++) {
778 ✗ tmp = .9f * tmp;
779 ✗ lpc[i] = (lpc[i] * tmp);
780 }
781 /* Add a zero */
782 ✗ lpc2[0] = lpc[0] + .8f;
783 ✗ lpc2[1] = lpc[1] + (c1 * lpc[0]);
784 ✗ lpc2[2] = lpc[2] + (c1 * lpc[1]);
785 ✗ lpc2[3] = lpc[3] + (c1 * lpc[2]);
786 ✗ lpc2[4] = (c1 * lpc[3]);
787 ✗ celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
788 ✗ }
789
790 ✗ static inline void dual_inner_prod(const float *x, const float *y01, const float *y02,
791 int N, float *xy1, float *xy2)
792 {
793 ✗ float xy01 = 0, xy02 = 0;
794
795 ✗ for (int i = 0; i < N; i++) {
796 ✗ xy01 += (x[i] * y01[i]);
797 ✗ xy02 += (x[i] * y02[i]);
798 }
799
800 ✗ *xy1 = xy01;
801 ✗ *xy2 = xy02;
802 ✗ }
803
804 ✗ static float compute_pitch_gain(float xy, float xx, float yy)
805 {
806 ✗ return xy / sqrtf(1.f + xx * yy);
807 }
808
809 static const uint8_t second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
810 ✗ static float remove_doubling(float *x, int maxperiod, int minperiod, int N,
811 int *T0_, int prev_period, float prev_gain)
812 {
813 int k, i, T, T0;
814 float g, g0;
815 float pg;
816 float xy,xx,yy,xy2;
817 float xcorr[3];
818 float best_xy, best_yy;
819 int offset;
820 int minperiod0;
821 float yy_lookup[PITCH_MAX_PERIOD+1];
822
823 ✗ minperiod0 = minperiod;
824 ✗ maxperiod /= 2;
825 ✗ minperiod /= 2;
826 ✗ *T0_ /= 2;
827 ✗ prev_period /= 2;
828 ✗ N /= 2;
829 ✗ x += maxperiod;
830 ✗ if (*T0_>=maxperiod)
831 ✗ *T0_=maxperiod-1;
832
833 ✗ T = T0 = *T0_;
834 ✗ dual_inner_prod(x, x, x-T0, N, &xx, &xy);
835 ✗ yy_lookup[0] = xx;
836 ✗ yy=xx;
837 ✗ for (i = 1; i <= maxperiod; i++) {
838 ✗ yy = yy+(x[-i] * x[-i])-(x[N-i] * x[N-i]);
839 ✗ yy_lookup[i] = FFMAX(0, yy);
840 }
841 ✗ yy = yy_lookup[T0];
842 ✗ best_xy = xy;
843 ✗ best_yy = yy;
844 ✗ g = g0 = compute_pitch_gain(xy, xx, yy);
845 /* Look for any pitch at T/k */
846 ✗ for (k = 2; k <= 15; k++) {
847 int T1, T1b;
848 float g1;
849 ✗ float cont=0;
850 float thresh;
851 ✗ T1 = (2*T0+k)/(2*k);
852 ✗ if (T1 < minperiod)
853 ✗ break;
854 /* Look for another strong correlation at T1b */
855 ✗ if (k==2)
856 {
857 ✗ if (T1+T0>maxperiod)
858 ✗ T1b = T0;
859 else
860 ✗ T1b = T0+T1;
861 } else
862 {
863 ✗ T1b = (2*second_check[k]*T0+k)/(2*k);
864 }
865 ✗ dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2);
866 ✗ xy = .5f * (xy + xy2);
867 ✗ yy = .5f * (yy_lookup[T1] + yy_lookup[T1b]);
868 ✗ g1 = compute_pitch_gain(xy, xx, yy);
869 ✗ if (FFABS(T1-prev_period)<=1)
870 ✗ cont = prev_gain;
871 ✗ else if (FFABS(T1-prev_period)<=2 && 5 * k * k < T0)
872 ✗ cont = prev_gain * .5f;
873 else
874 ✗ cont = 0;
875 ✗ thresh = FFMAX(.3f, (.7f * g0) - cont);
876 /* Bias against very high pitch (very short period) to avoid false-positives
877 due to short-term correlation */
878 ✗ if (T1<3*minperiod)
879 ✗ thresh = FFMAX(.4f, (.85f * g0) - cont);
880 ✗ else if (T1<2*minperiod)
881 ✗ thresh = FFMAX(.5f, (.9f * g0) - cont);
882 ✗ if (g1 > thresh)
883 {
884 ✗ best_xy = xy;
885 ✗ best_yy = yy;
886 ✗ T = T1;
887 ✗ g = g1;
888 }
889 }
890 ✗ best_xy = FFMAX(0, best_xy);
891 ✗ if (best_yy <= best_xy)
892 ✗ pg = Q15ONE;
893 else
894 ✗ pg = best_xy/(best_yy + 1);
895
896 ✗ for (k = 0; k < 3; k++)
897 ✗ xcorr[k] = celt_inner_prod(x, x-(T+k-1), N);
898 ✗ if ((xcorr[2]-xcorr[0]) > .7f * (xcorr[1]-xcorr[0]))
899 ✗ offset = 1;
900 ✗ else if ((xcorr[0]-xcorr[2]) > (.7f * (xcorr[1] - xcorr[2])))
901 ✗ offset = -1;
902 else
903 ✗ offset = 0;
904 ✗ if (pg > g)
905 ✗ pg = g;
906 ✗ *T0_ = 2*T+offset;
907
908 ✗ if (*T0_<minperiod0)
909 ✗ *T0_=minperiod0;
910 ✗ return pg;
911 }
912
913 ✗ static void find_best_pitch(float *xcorr, float *y, int len,
914 int max_pitch, int *best_pitch)
915 {
916 float best_num[2];
917 float best_den[2];
918 ✗ float Syy = 1.f;
919
920 ✗ best_num[0] = -1;
921 ✗ best_num[1] = -1;
922 ✗ best_den[0] = 0;
923 ✗ best_den[1] = 0;
924 ✗ best_pitch[0] = 0;
925 ✗ best_pitch[1] = 1;
926
927 ✗ for (int j = 0; j < len; j++)
928 ✗ Syy += y[j] * y[j];
929
930 ✗ for (int i = 0; i < max_pitch; i++) {
931 ✗ if (xcorr[i]>0) {
932 float num;
933 float xcorr16;
934
935 ✗ xcorr16 = xcorr[i];
936 /* Considering the range of xcorr16, this should avoid both underflows
937 and overflows (inf) when squaring xcorr16 */
938 ✗ xcorr16 *= 1e-12f;
939 ✗ num = xcorr16 * xcorr16;
940 ✗ if ((num * best_den[1]) > (best_num[1] * Syy)) {
941 ✗ if ((num * best_den[0]) > (best_num[0] * Syy)) {
942 ✗ best_num[1] = best_num[0];
943 ✗ best_den[1] = best_den[0];
944 ✗ best_pitch[1] = best_pitch[0];
945 ✗ best_num[0] = num;
946 ✗ best_den[0] = Syy;
947 ✗ best_pitch[0] = i;
948 } else {
949 ✗ best_num[1] = num;
950 ✗ best_den[1] = Syy;
951 ✗ best_pitch[1] = i;
952 }
953 }
954 }
955 ✗ Syy += y[i+len]*y[i+len] - y[i] * y[i];
956 ✗ Syy = FFMAX(1, Syy);
957 }
958 ✗ }
959
960 ✗ static void pitch_search(const float *x_lp, float *y,
961 int len, int max_pitch, int *pitch)
962 {
963 int lag;
964 ✗ int best_pitch[2]={0,0};
965 int offset;
966
967 float x_lp4[WINDOW_SIZE];
968 float y_lp4[WINDOW_SIZE];
969 float xcorr[WINDOW_SIZE];
970
971 ✗ lag = len+max_pitch;
972
973 /* Downsample by 2 again */
974 ✗ for (int j = 0; j < len >> 2; j++)
975 ✗ x_lp4[j] = x_lp[2*j];
976 ✗ for (int j = 0; j < lag >> 2; j++)
977 ✗ y_lp4[j] = y[2*j];
978
979 /* Coarse search with 4x decimation */
980
981 ✗ celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2);
982
983 ✗ find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch);
984
985 /* Finer search with 2x decimation */
986 ✗ for (int i = 0; i < max_pitch >> 1; i++) {
987 float sum;
988 ✗ xcorr[i] = 0;
989 ✗ if (FFABS(i-2*best_pitch[0])>2 && FFABS(i-2*best_pitch[1])>2)
990 ✗ continue;
991 ✗ sum = celt_inner_prod(x_lp, y+i, len>>1);
992 ✗ xcorr[i] = FFMAX(-1, sum);
993 }
994
995 ✗ find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch);
996
997 /* Refine by pseudo-interpolation */
998 ✗ if (best_pitch[0] > 0 && best_pitch[0] < (max_pitch >> 1) - 1) {
999 float a, b, c;
1000
1001 ✗ a = xcorr[best_pitch[0] - 1];
1002 ✗ b = xcorr[best_pitch[0]];
1003 ✗ c = xcorr[best_pitch[0] + 1];
1004 ✗ if (c - a > .7f * (b - a))
1005 ✗ offset = 1;
1006 ✗ else if (a - c > .7f * (b-c))
1007 ✗ offset = -1;
1008 else
1009 ✗ offset = 0;
1010 } else {
1011 ✗ offset = 0;
1012 }
1013
1014 ✗ *pitch = 2 * best_pitch[0] - offset;
1015 ✗ }
1016
1017 ✗ static void dct(AudioRNNContext *s, float *out, const float *in)
1018 {
1019 ✗ for (int i = 0; i < NB_BANDS; i++) {
1020 float sum;
1021
1022 ✗ sum = s->fdsp->scalarproduct_float(in, s->dct_table[i], FFALIGN(NB_BANDS, 4));
1023 ✗ out[i] = sum * sqrtf(2.f / 22);
1024 }
1025 ✗ }
1026
1027 ✗ static int compute_frame_features(AudioRNNContext *s, DenoiseState *st, AVComplexFloat *X, AVComplexFloat *P,
1028 float *Ex, float *Ep, float *Exp, float *features, const float *in)
1029 {
1030 ✗ float E = 0;
1031 float *ceps_0, *ceps_1, *ceps_2;
1032 ✗ float spec_variability = 0;
1033 ✗ LOCAL_ALIGNED_32(float, Ly, [FFALIGN(NB_BANDS, 4)]);
1034 ✗ LOCAL_ALIGNED_32(float, p, [WINDOW_SIZE]);
1035 float pitch_buf[PITCH_BUF_SIZE>>1];
1036 int pitch_index;
1037 float gain;
1038 float *(pre[1]);
1039 float tmp[NB_BANDS];
1040 float follow, logMax;
1041
1042 ✗ frame_analysis(s, st, X, Ex, in);
1043 ✗ RNN_MOVE(st->pitch_buf, &st->pitch_buf[FRAME_SIZE], PITCH_BUF_SIZE-FRAME_SIZE);
1044 ✗ RNN_COPY(&st->pitch_buf[PITCH_BUF_SIZE-FRAME_SIZE], in, FRAME_SIZE);
1045 ✗ pre[0] = &st->pitch_buf[0];
1046 ✗ pitch_downsample(pre, pitch_buf, PITCH_BUF_SIZE, 1);
1047 ✗ pitch_search(pitch_buf+(PITCH_MAX_PERIOD>>1), pitch_buf, PITCH_FRAME_SIZE,
1048 PITCH_MAX_PERIOD-3*PITCH_MIN_PERIOD, &pitch_index);
1049 ✗ pitch_index = PITCH_MAX_PERIOD-pitch_index;
1050
1051 ✗ gain = remove_doubling(pitch_buf, PITCH_MAX_PERIOD, PITCH_MIN_PERIOD,
1052 PITCH_FRAME_SIZE, &pitch_index, st->last_period, st->last_gain);
1053 ✗ st->last_period = pitch_index;
1054 ✗ st->last_gain = gain;
1055
1056 ✗ for (int i = 0; i < WINDOW_SIZE; i++)
1057 ✗ p[i] = st->pitch_buf[PITCH_BUF_SIZE-WINDOW_SIZE-pitch_index+i];
1058
1059 ✗ s->fdsp->vector_fmul(p, p, s->window, WINDOW_SIZE);
1060 ✗ forward_transform(st, P, p);
1061 ✗ compute_band_energy(Ep, P);
1062 ✗ compute_band_corr(Exp, X, P);
1063
1064 ✗ for (int i = 0; i < NB_BANDS; i++)
1065 ✗ Exp[i] = Exp[i] / sqrtf(.001f+Ex[i]*Ep[i]);
1066
1067 ✗ memset(Exp + NB_BANDS, 0, (FFALIGN(NB_BANDS, 4) - NB_BANDS) * sizeof(*Exp));
1068 ✗ dct(s, tmp, Exp);
1069
1070 ✗ for (int i = 0; i < NB_DELTA_CEPS; i++)
1071 ✗ features[NB_BANDS+2*NB_DELTA_CEPS+i] = tmp[i];
1072
1073 ✗ features[NB_BANDS+2*NB_DELTA_CEPS] -= 1.3;
1074 ✗ features[NB_BANDS+2*NB_DELTA_CEPS+1] -= 0.9;
1075 ✗ features[NB_BANDS+3*NB_DELTA_CEPS] = .01*(pitch_index-300);
1076 ✗ logMax = -2;
1077 ✗ follow = -2;
1078
1079 ✗ for (int i = 0; i < NB_BANDS; i++) {
1080 ✗ Ly[i] = log10f(1e-2f + Ex[i]);
1081 ✗ Ly[i] = FFMAX(logMax-7, FFMAX(follow-1.5, Ly[i]));
1082 ✗ logMax = FFMAX(logMax, Ly[i]);
1083 ✗ follow = FFMAX(follow-1.5, Ly[i]);
1084 ✗ E += Ex[i];
1085 }
1086
1087 ✗ if (E < 0.04f) {
1088 /* If there's no audio, avoid messing up the state. */
1089 ✗ RNN_CLEAR(features, NB_FEATURES);
1090 ✗ return 1;
1091 }
1092
1093 ✗ memset(Ly + NB_BANDS, 0, (FFALIGN(NB_BANDS, 4) - NB_BANDS) * sizeof(*Ly));
1094 ✗ dct(s, features, Ly);
1095 ✗ features[0] -= 12;
1096 ✗ features[1] -= 4;
1097 ✗ ceps_0 = st->cepstral_mem[st->memid];
1098 ✗ ceps_1 = (st->memid < 1) ? st->cepstral_mem[CEPS_MEM+st->memid-1] : st->cepstral_mem[st->memid-1];
1099 ✗ ceps_2 = (st->memid < 2) ? st->cepstral_mem[CEPS_MEM+st->memid-2] : st->cepstral_mem[st->memid-2];
1100
1101 ✗ for (int i = 0; i < NB_BANDS; i++)
1102 ✗ ceps_0[i] = features[i];
1103
1104 ✗ st->memid++;
1105 ✗ for (int i = 0; i < NB_DELTA_CEPS; i++) {
1106 ✗ features[i] = ceps_0[i] + ceps_1[i] + ceps_2[i];
1107 ✗ features[NB_BANDS+i] = ceps_0[i] - ceps_2[i];
1108 ✗ features[NB_BANDS+NB_DELTA_CEPS+i] = ceps_0[i] - 2*ceps_1[i] + ceps_2[i];
1109 }
1110 /* Spectral variability features. */
1111 ✗ if (st->memid == CEPS_MEM)
1112 ✗ st->memid = 0;
1113
1114 ✗ for (int i = 0; i < CEPS_MEM; i++) {
1115 ✗ float mindist = 1e15f;
1116 ✗ for (int j = 0; j < CEPS_MEM; j++) {
1117 ✗ float dist = 0.f;
1118 ✗ for (int k = 0; k < NB_BANDS; k++) {
1119 float tmp;
1120
1121 ✗ tmp = st->cepstral_mem[i][k] - st->cepstral_mem[j][k];
1122 ✗ dist += tmp*tmp;
1123 }
1124
1125 ✗ if (j != i)
1126 ✗ mindist = FFMIN(mindist, dist);
1127 }
1128
1129 ✗ spec_variability += mindist;
1130 }
1131
1132 ✗ features[NB_BANDS+3*NB_DELTA_CEPS+1] = spec_variability/CEPS_MEM-2.1;
1133
1134 ✗ return 0;
1135 }
1136
1137 ✗ static void interp_band_gain(float *g, const float *bandE)
1138 {
1139 ✗ memset(g, 0, sizeof(*g) * FREQ_SIZE);
1140
1141 ✗ for (int i = 0; i < NB_BANDS - 1; i++) {
1142 ✗ const int band_size = (eband5ms[i + 1] - eband5ms[i]) << FRAME_SIZE_SHIFT;
1143
1144 ✗ for (int j = 0; j < band_size; j++) {
1145 ✗ float frac = (float)j / band_size;
1146
1147 ✗ g[(eband5ms[i] << FRAME_SIZE_SHIFT) + j] = (1.f - frac) * bandE[i] + frac * bandE[i + 1];
1148 }
1149 }
1150 ✗ }
1151
1152 ✗ static void pitch_filter(AVComplexFloat *X, const AVComplexFloat *P, const float *Ex, const float *Ep,
1153 const float *Exp, const float *g)
1154 {
1155 float newE[NB_BANDS];
1156 float r[NB_BANDS];
1157 float norm[NB_BANDS];
1158 ✗ float rf[FREQ_SIZE] = {0};
1159 ✗ float normf[FREQ_SIZE]={0};
1160
1161 ✗ for (int i = 0; i < NB_BANDS; i++) {
1162 ✗ if (Exp[i]>g[i]) r[i] = 1;
1163 ✗ else r[i] = SQUARE(Exp[i])*(1-SQUARE(g[i]))/(.001 + SQUARE(g[i])*(1-SQUARE(Exp[i])));
1164 ✗ r[i] = sqrtf(av_clipf(r[i], 0, 1));
1165 ✗ r[i] *= sqrtf(Ex[i]/(1e-8+Ep[i]));
1166 }
1167 ✗ interp_band_gain(rf, r);
1168 ✗ for (int i = 0; i < FREQ_SIZE; i++) {
1169 ✗ X[i].re += rf[i]*P[i].re;
1170 ✗ X[i].im += rf[i]*P[i].im;
1171 }
1172 ✗ compute_band_energy(newE, X);
1173 ✗ for (int i = 0; i < NB_BANDS; i++) {
1174 ✗ norm[i] = sqrtf(Ex[i] / (1e-8+newE[i]));
1175 }
1176 ✗ interp_band_gain(normf, norm);
1177 ✗ for (int i = 0; i < FREQ_SIZE; i++) {
1178 ✗ X[i].re *= normf[i];
1179 ✗ X[i].im *= normf[i];
1180 }
1181 ✗ }
1182
1183 static const float tansig_table[201] = {
1184 0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
1185 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
1186 0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
1187 0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
1188 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
1189 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
1190 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
1191 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
1192 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
1193 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
1194 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
1195 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
1196 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
1197 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
1198 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
1199 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
1200 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
1201 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
1202 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
1203 0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
1204 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
1205 0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
1206 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
1207 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
1208 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
1209 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
1210 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
1211 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
1212 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
1213 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
1214 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
1215 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
1216 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
1217 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
1218 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
1219 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
1220 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
1221 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
1222 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
1223 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
1224 1.000000f,
1225 };
1226
1227 ✗ static inline float tansig_approx(float x)
1228 {
1229 float y, dy;
1230 ✗ float sign=1;
1231 int i;
1232
1233 /* Tests are reversed to catch NaNs */
1234 ✗ if (!(x<8))
1235 ✗ return 1;
1236 ✗ if (!(x>-8))
1237 ✗ return -1;
1238 /* Another check in case of -ffast-math */
1239
1240 ✗ if (isnan(x))
1241 ✗ return 0;
1242
1243 ✗ if (x < 0) {
1244 ✗ x=-x;
1245 ✗ sign=-1;
1246 }
1247 ✗ i = (int)floor(.5f+25*x);
1248 ✗ x -= .04f*i;
1249 ✗ y = tansig_table[i];
1250 ✗ dy = 1-y*y;
1251 ✗ y = y + x*dy*(1 - y*x);
1252 ✗ return sign*y;
1253 }
1254
1255 ✗ static inline float sigmoid_approx(float x)
1256 {
1257 ✗ return .5f + .5f*tansig_approx(.5f*x);
1258 }
1259
1260 ✗ static void compute_dense(const DenseLayer *layer, float *output, const float *input)
1261 {
1262 ✗ const int N = layer->nb_neurons, M = layer->nb_inputs, stride = N;
1263
1264 ✗ for (int i = 0; i < N; i++) {
1265 /* Compute update gate. */
1266 ✗ float sum = layer->bias[i];
1267
1268 ✗ for (int j = 0; j < M; j++)
1269 ✗ sum += layer->input_weights[j * stride + i] * input[j];
1270
1271 ✗ output[i] = WEIGHTS_SCALE * sum;
1272 }
1273
1274 ✗ if (layer->activation == ACTIVATION_SIGMOID) {
1275 ✗ for (int i = 0; i < N; i++)
1276 ✗ output[i] = sigmoid_approx(output[i]);
1277 ✗ } else if (layer->activation == ACTIVATION_TANH) {
1278 ✗ for (int i = 0; i < N; i++)
1279 ✗ output[i] = tansig_approx(output[i]);
1280 ✗ } else if (layer->activation == ACTIVATION_RELU) {
1281 ✗ for (int i = 0; i < N; i++)
1282 ✗ output[i] = FFMAX(0, output[i]);
1283 } else {
1284 ✗ av_assert0(0);
1285 }
1286 ✗ }
1287
1288 ✗ static void compute_gru(AudioRNNContext *s, const GRULayer *gru, float *state, const float *input)
1289 {
1290 ✗ LOCAL_ALIGNED_32(float, z, [MAX_NEURONS]);
1291 ✗ LOCAL_ALIGNED_32(float, r, [MAX_NEURONS]);
1292 ✗ LOCAL_ALIGNED_32(float, h, [MAX_NEURONS]);
1293 ✗ const int M = gru->nb_inputs;
1294 ✗ const int N = gru->nb_neurons;
1295 ✗ const int AN = FFALIGN(N, 4);
1296 ✗ const int AM = FFALIGN(M, 4);
1297 ✗ const int stride = 3 * AN, istride = 3 * AM;
1298
1299 ✗ for (int i = 0; i < N; i++) {
1300 /* Compute update gate. */
1301 ✗ float sum = gru->bias[i];
1302
1303 ✗ sum += s->fdsp->scalarproduct_float(gru->input_weights + i * istride, input, AM);
1304 ✗ sum += s->fdsp->scalarproduct_float(gru->recurrent_weights + i * stride, state, AN);
1305 ✗ z[i] = sigmoid_approx(WEIGHTS_SCALE * sum);
1306 }
1307
1308 ✗ for (int i = 0; i < N; i++) {
1309 /* Compute reset gate. */
1310 ✗ float sum = gru->bias[N + i];
1311
1312 ✗ sum += s->fdsp->scalarproduct_float(gru->input_weights + AM + i * istride, input, AM);
1313 ✗ sum += s->fdsp->scalarproduct_float(gru->recurrent_weights + AN + i * stride, state, AN);
1314 ✗ r[i] = sigmoid_approx(WEIGHTS_SCALE * sum);
1315 }
1316
1317 ✗ for (int i = 0; i < N; i++) {
1318 /* Compute output. */
1319 ✗ float sum = gru->bias[2 * N + i];
1320
1321 ✗ sum += s->fdsp->scalarproduct_float(gru->input_weights + 2 * AM + i * istride, input, AM);
1322 ✗ for (int j = 0; j < N; j++)
1323 ✗ sum += gru->recurrent_weights[2 * AN + i * stride + j] * state[j] * r[j];
1324
1325 ✗ if (gru->activation == ACTIVATION_SIGMOID)
1326 ✗ sum = sigmoid_approx(WEIGHTS_SCALE * sum);
1327 ✗ else if (gru->activation == ACTIVATION_TANH)
1328 ✗ sum = tansig_approx(WEIGHTS_SCALE * sum);
1329 ✗ else if (gru->activation == ACTIVATION_RELU)
1330 ✗ sum = FFMAX(0, WEIGHTS_SCALE * sum);
1331 else
1332 ✗ av_assert0(0);
1333 ✗ h[i] = z[i] * state[i] + (1.f - z[i]) * sum;
1334 }
1335
1336 ✗ RNN_COPY(state, h, N);
1337 ✗ }
1338
1339 ✗ static void compute_rnn(AudioRNNContext *s, RNNState *rnn, float *gains, float *vad, const float *input)
1340 {
1341 ✗ LOCAL_ALIGNED_32(float, dense_out, [MAX_NEURONS]);
1342 ✗ LOCAL_ALIGNED_32(float, noise_input, [MAX_NEURONS * 3]);
1343 ✗ LOCAL_ALIGNED_32(float, denoise_input, [MAX_NEURONS * 3]);
1344
1345 ✗ memset(dense_out, 0, MAX_NEURONS * sizeof(float));
1346 ✗ memset(noise_input, 0, MAX_NEURONS * 3 * sizeof(float));
1347 ✗ memset(denoise_input, 0, MAX_NEURONS * 3 * sizeof(float));
1348 ✗ compute_dense(rnn->model->input_dense, dense_out, input);
1349 ✗ compute_gru(s, rnn->model->vad_gru, rnn->vad_gru_state, dense_out);
1350 ✗ compute_dense(rnn->model->vad_output, vad, rnn->vad_gru_state);
1351
1352 ✗ memcpy(noise_input, dense_out, rnn->model->input_dense_size * sizeof(float));
1353 ✗ memcpy(noise_input + rnn->model->input_dense_size,
1354 ✗ rnn->vad_gru_state, rnn->model->vad_gru_size * sizeof(float));
1355 ✗ memcpy(noise_input + rnn->model->input_dense_size + rnn->model->vad_gru_size,
1356 input, NB_FEATURES * sizeof(float));
1357
1358 ✗ compute_gru(s, rnn->model->noise_gru, rnn->noise_gru_state, noise_input);
1359
1360 ✗ memcpy(denoise_input, rnn->vad_gru_state, rnn->model->vad_gru_size * sizeof(float));
1361 ✗ memcpy(denoise_input + rnn->model->vad_gru_size,
1362 ✗ rnn->noise_gru_state, rnn->model->noise_gru_size * sizeof(float));
1363 ✗ memcpy(denoise_input + rnn->model->vad_gru_size + rnn->model->noise_gru_size,
1364 input, NB_FEATURES * sizeof(float));
1365
1366 ✗ compute_gru(s, rnn->model->denoise_gru, rnn->denoise_gru_state, denoise_input);
1367 ✗ compute_dense(rnn->model->denoise_output, gains, rnn->denoise_gru_state);
1368 ✗ }
1369
1370 ✗ static float rnnoise_channel(AudioRNNContext *s, DenoiseState *st, float *out, const float *in,
1371 int disabled)
1372 {
1373 AVComplexFloat X[FREQ_SIZE];
1374 AVComplexFloat P[WINDOW_SIZE];
1375 float x[FRAME_SIZE];
1376 float Ex[NB_BANDS], Ep[NB_BANDS];
1377 ✗ LOCAL_ALIGNED_32(float, Exp, [FFALIGN(NB_BANDS, 4)]);
1378 float features[NB_FEATURES];
1379 float g[NB_BANDS];
1380 float gf[FREQ_SIZE];
1381 ✗ float vad_prob = 0;
1382 ✗ float *history = st->history;
1383 static const float a_hp[2] = {-1.99599, 0.99600};
1384 static const float b_hp[2] = {-2, 1};
1385 int silence;
1386
1387 ✗ biquad(x, st->mem_hp_x, in, b_hp, a_hp, FRAME_SIZE);
1388 ✗ silence = compute_frame_features(s, st, X, P, Ex, Ep, Exp, features, x);
1389
1390 ✗ if (!silence && !disabled) {
1391 ✗ compute_rnn(s, &st->rnn[0], g, &vad_prob, features);
1392 ✗ pitch_filter(X, P, Ex, Ep, Exp, g);
1393 ✗ for (int i = 0; i < NB_BANDS; i++) {
1394 ✗ float alpha = .6f;
1395
1396 ✗ g[i] = FFMAX(g[i], alpha * st->lastg[i]);
1397 ✗ st->lastg[i] = g[i];
1398 }
1399
1400 ✗ interp_band_gain(gf, g);
1401
1402 ✗ for (int i = 0; i < FREQ_SIZE; i++) {
1403 ✗ X[i].re *= gf[i];
1404 ✗ X[i].im *= gf[i];
1405 }
1406 }
1407
1408 ✗ frame_synthesis(s, st, out, X);
1409 ✗ memcpy(history, in, FRAME_SIZE * sizeof(*history));
1410
1411 ✗ return vad_prob;
1412 }
1413
1414 typedef struct ThreadData {
1415 AVFrame *in, *out;
1416 } ThreadData;
1417
1418 ✗ static int rnnoise_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1419 {
1420 ✗ AudioRNNContext *s = ctx->priv;
1421 ✗ ThreadData *td = arg;
1422 ✗ AVFrame *in = td->in;
1423 ✗ AVFrame *out = td->out;
1424 ✗ const int start = ff_slice_pos(out->ch_layout.nb_channels, jobnr, nb_jobs);
1425 ✗ const int end = ff_slice_pos(out->ch_layout.nb_channels, jobnr + 1, nb_jobs);
1426
1427 ✗ for (int ch = start; ch < end; ch++) {
1428 ✗ rnnoise_channel(s, &s->st[ch],
1429 ✗ (float *)out->extended_data[ch],
1430 ✗ (const float *)in->extended_data[ch],
1431 ctx->is_disabled);
1432 }
1433
1434 ✗ return 0;
1435 }
1436
1437 ✗ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1438 {
1439 ✗ AVFilterContext *ctx = inlink->dst;
1440 ✗ AVFilterLink *outlink = ctx->outputs[0];
1441 ✗ AVFrame *out = NULL;
1442 ThreadData td;
1443
1444 ✗ out = ff_get_audio_buffer(outlink, FRAME_SIZE);
1445 ✗ if (!out) {
1446 ✗ av_frame_free(&in);
1447 ✗ return AVERROR(ENOMEM);
1448 }
1449 ✗ av_frame_copy_props(out, in);
1450
1451 ✗ td.in = in; td.out = out;
1452 ✗ ff_filter_execute(ctx, rnnoise_channels, &td, NULL,
1453 ✗ FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
1454
1455 ✗ av_frame_free(&in);
1456 ✗ return ff_filter_frame(outlink, out);
1457 }
1458
1459 ✗ static int activate(AVFilterContext *ctx)
1460 {
1461 ✗ AVFilterLink *inlink = ctx->inputs[0];
1462 ✗ AVFilterLink *outlink = ctx->outputs[0];
1463 ✗ AVFrame *in = NULL;
1464 int ret;
1465
1466 ✗ FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
1467
1468 ✗ ret = ff_inlink_consume_samples(inlink, FRAME_SIZE, FRAME_SIZE, &in);
1469 ✗ if (ret < 0)
1470 ✗ return ret;
1471
1472 ✗ if (ret > 0)
1473 ✗ return filter_frame(inlink, in);
1474
1475 ✗ FF_FILTER_FORWARD_STATUS(inlink, outlink);
1476 ✗ FF_FILTER_FORWARD_WANTED(outlink, inlink);
1477
1478 ✗ return FFERROR_NOT_READY;
1479 }
1480
1481 ✗ static int open_model(AVFilterContext *ctx, RNNModel **model)
1482 {
1483 ✗ AudioRNNContext *s = ctx->priv;
1484 int ret;
1485 FILE *f;
1486
1487 ✗ if (!s->model_name)
1488 ✗ return AVERROR(EINVAL);
1489 ✗ f = avpriv_fopen_utf8(s->model_name, "r");
1490 ✗ if (!f) {
1491 ✗ av_log(ctx, AV_LOG_ERROR, "Failed to open model file: %s\n", s->model_name);
1492 ✗ return AVERROR(EINVAL);
1493 }
1494
1495 ✗ ret = rnnoise_model_from_file(f, model);
1496 ✗ fclose(f);
1497 ✗ if (!*model || ret < 0)
1498 ✗ return ret;
1499
1500 ✗ return 0;
1501 }
1502
1503 ✗ static av_cold int init(AVFilterContext *ctx)
1504 {
1505 ✗ AudioRNNContext *s = ctx->priv;
1506 int ret;
1507
1508 ✗ s->fdsp = avpriv_float_dsp_alloc(0);
1509 ✗ if (!s->fdsp)
1510 ✗ return AVERROR(ENOMEM);
1511
1512 ✗ ret = open_model(ctx, &s->model[0]);
1513 ✗ if (ret < 0)
1514 ✗ return ret;
1515
1516 ✗ for (int i = 0; i < FRAME_SIZE; i++) {
1517 ✗ s->window[i] = sin(.5*M_PI*sin(.5*M_PI*(i+.5)/FRAME_SIZE) * sin(.5*M_PI*(i+.5)/FRAME_SIZE));
1518 ✗ s->window[WINDOW_SIZE - 1 - i] = s->window[i];
1519 }
1520
1521 ✗ for (int i = 0; i < NB_BANDS; i++) {
1522 ✗ for (int j = 0; j < NB_BANDS; j++) {
1523 ✗ s->dct_table[j][i] = cosf((i + .5f) * j * M_PI / NB_BANDS);
1524 ✗ if (j == 0)
1525 ✗ s->dct_table[j][i] *= sqrtf(.5);
1526 }
1527 }
1528
1529 ✗ return 0;
1530 }
1531
1532 ✗ static void free_model(AVFilterContext *ctx, int n)
1533 {
1534 ✗ AudioRNNContext *s = ctx->priv;
1535
1536 ✗ rnnoise_model_free(s->model[n]);
1537 ✗ s->model[n] = NULL;
1538
1539 ✗ for (int ch = 0; ch < s->channels && s->st; ch++) {
1540 ✗ av_freep(&s->st[ch].rnn[n].vad_gru_state);
1541 ✗ av_freep(&s->st[ch].rnn[n].noise_gru_state);
1542 ✗ av_freep(&s->st[ch].rnn[n].denoise_gru_state);
1543 }
1544 ✗ }
1545
1546 ✗ static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1547 char *res, int res_len, int flags)
1548 {
1549 ✗ AudioRNNContext *s = ctx->priv;
1550 int ret;
1551
1552 ✗ ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1553 ✗ if (ret < 0)
1554 ✗ return ret;
1555
1556 ✗ ret = open_model(ctx, &s->model[1]);
1557 ✗ if (ret < 0)
1558 ✗ return ret;
1559
1560 ✗ FFSWAP(RNNModel *, s->model[0], s->model[1]);
1561 ✗ for (int ch = 0; ch < s->channels; ch++)
1562 ✗ FFSWAP(RNNState, s->st[ch].rnn[0], s->st[ch].rnn[1]);
1563
1564 ✗ ret = config_input(ctx->inputs[0]);
1565 ✗ if (ret < 0) {
1566 ✗ for (int ch = 0; ch < s->channels; ch++)
1567 ✗ FFSWAP(RNNState, s->st[ch].rnn[0], s->st[ch].rnn[1]);
1568 ✗ FFSWAP(RNNModel *, s->model[0], s->model[1]);
1569 ✗ return ret;
1570 }
1571
1572 ✗ free_model(ctx, 1);
1573 ✗ return 0;
1574 }
1575
1576 ✗ static av_cold void uninit(AVFilterContext *ctx)
1577 {
1578 ✗ AudioRNNContext *s = ctx->priv;
1579
1580 ✗ av_freep(&s->fdsp);
1581 ✗ free_model(ctx, 0);
1582 ✗ for (int ch = 0; ch < s->channels && s->st; ch++) {
1583 ✗ av_tx_uninit(&s->st[ch].tx);
1584 ✗ av_tx_uninit(&s->st[ch].txi);
1585 }
1586 ✗ av_freep(&s->st);
1587 ✗ }
1588
1589 static const AVFilterPad inputs[] = {
1590 {
1591 .name = "default",
1592 .type = AVMEDIA_TYPE_AUDIO,
1593 .config_props = config_input,
1594 },
1595 };
1596
1597 #define OFFSET(x) offsetof(AudioRNNContext, x)
1598 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
1599
1600 static const AVOption arnndn_options[] = {
1601 { "model", "set model name", OFFSET(model_name), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, AF },
1602 { "m", "set model name", OFFSET(model_name), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, AF },
1603 { "mix", "set output vs input mix", OFFSET(mix), AV_OPT_TYPE_FLOAT, {.dbl=1.0},-1, 1, AF },
1604 { NULL }
1605 };
1606
1607 AVFILTER_DEFINE_CLASS(arnndn);
1608
1609 const FFFilter ff_af_arnndn = {
1610 .p.name = "arnndn",
1611 .p.description = NULL_IF_CONFIG_SMALL("Reduce noise from speech using Recurrent Neural Networks."),
1612 .p.priv_class = &arnndn_class,
1613 .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
1614 AVFILTER_FLAG_SLICE_THREADS,
1615 .priv_size = sizeof(AudioRNNContext),
1616 .activate = activate,
1617 .init = init,
1618 .uninit = uninit,
1619 FILTER_INPUTS(inputs),
1620 FILTER_OUTPUTS(ff_audio_default_filterpad),
1621 FILTER_QUERY_FUNC2(query_formats),
1622 .process_command = process_command,
1623 };
1624