History

avfilter/af_afir: add support for double sample format

Paul B Mahol committed 4 years ago

Commit 163e7371 parent e6f0cec5 files · +623 −415Browse files

Showing the changes to libavfilter (4 of 5 files). Show all

Unified · Split

4 files
  1. libavfilter/af_afir.c +96 −415
  2. libavfilter/af_afir.h +99 −0
  3. libavfilter/af_afirdsp.h +20 −0
  4. libavfilter/afir_template.c +392 −0
libavfilter/af_afir.c+96−415
@@ -42,208 +42,78 @@ · 41 unmodified lines
4242 #include "filters.h"
4343 #include "formats.h"
4444 #include "internal.h"
45+#include "af_afir.h"
4546 #include "af_afirdsp.h"
4647
47−typedef struct AudioFIRSegment {
48− int nb_partitions;
49− int part_size;
50− int block_size;
51− int fft_length;
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;
48+static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
49+{
50+ const uint8_t *font;
51+ int font_height;
52+ int i;
10853
109− AudioFIRDSPContext afirdsp;
110− AVFloatDSPContext *fdsp;
111−} AudioFIRContext;
54+ font = avpriv_cga_font, font_height = 8;
11255
113−static void direct(const float *in, const AVComplexFloat *ir, int len, float *out)
114−{
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−}
56+ for (i = 0; txt[i]; i++) {
57+ int char_y, mask;
11958
120−static void fir_fadd(AudioFIRContext *s, float *dst, const float *src, int nb_samples)
121−{
122− if ((nb_samples & 15) == 0 && nb_samples >= 16) {
123− s->fdsp->vector_fmac_scalar(dst, src, 1.f, nb_samples);
124− } else {
125− for (int n = 0; n < nb_samples; n++)
126− dst[n] += src[n];
59+ uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4;
60+ for (char_y = 0; char_y < font_height; char_y++) {
61+ for (mask = 0x80; mask; mask >>= 1) {
62+ if (font[txt[i] * font_height + char_y] & mask)
63+ AV_WL32(p, color);
64+ p += 4;
65+ }
66+ p += pic->linesize[0] - 8 * 4;
67+ }
12768 }
12869 }
12970
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)
13172 {
132− AudioFIRContext *s = ctx->priv;
133− const float *in = (const float *)s->in->extended_data[ch] + offset;
134− float *blockin, *blockout, *buf, *ptr = (float *)out->extended_data[ch] + offset;
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);
73+ int dx = FFABS(x1-x0);
74+ int dy = FFABS(y1-y0), sy = y0 < y1 ? 1 : -1;
75+ int err = (dx>dy ? dx : -dy) / 2, e2;
17476
175− if (j == 0)
176− j = seg->nb_partitions;
177− j--;
178− }
77+ for (;;) {
78+ AV_WL32(out->data[0] + y0 * out->linesize[0] + x0 * 4, color);
17979
180− seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions;
80+ if (x0 == x1 && y0 == y1)
81+ break;
18182
182− memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src));
83+ e2 = err;
18384
184− for (n = 0; n < nb_samples; n++) {
185− ptr[n] += dst[n];
186− }
187− continue;
85+ if (e2 >-dx) {
86+ err -= dy;
87+ x0--;
18888 }
18989
190− memset(sumin, 0, sizeof(*sumin) * seg->fft_length);
191− blockin = (float *)seg->blockin->extended_data[ch] + seg->part_index[ch] * seg->block_size;
192− blockout = (float *)seg->blockout->extended_data[ch] + seg->part_index[ch] * seg->block_size;
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--;
90+ if (e2 < dy) {
91+ err += dx;
92+ y0 += sy;
21193 }
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);
22894 }
95+}
22996
230− if (s->min_part_size >= 8) {
231− s->fdsp->vector_fmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 4));
232− emms_c();
233− } else {
234− for (n = 0; n < nb_samples; n++)
235− ptr[n] *= s->wet_gain;
236− }
97+#define DEPTH 32
98+#include "afir_template.c"
23799
238− return 0;
239−}
100+#undef DEPTH
101+#define DEPTH 64
102+#include "afir_template.c"
240103
241104 static int fir_channel(AVFilterContext *ctx, AVFrame *out, int ch)
242105 {
243106 AudioFIRContext *s = ctx->priv;
244107
245108 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+ }
247117 }
248118
249119 return 0;
@@ -284,144 +154,6 @@ static int fir_frame(AudioFIRContext *s, AVFrame *in, AVFilterLink *outlink) · 34 unmodified lines
284154 return ff_filter_frame(outlink, out);
285155 }
286156
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−
425157 static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg,
426158 int offset, int nb_partitions, int part_size)
427159 {
@@ -446,9 +178,20 @@ static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg, · 18 unmodified lines
446178 return AVERROR(ENOMEM);
447179
448180 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;
450− av_tx_init(&seg->tx[ch], &seg->tx_fn, AV_TX_FLOAT_RDFT, 0, 2 * part_size, &scale, 0);
451− av_tx_init(&seg->itx[ch], &seg->itx_fn, AV_TX_FLOAT_RDFT, 1, 2 * part_size, &iscale, 0);
181+ double dscale = 1.0, idscale = 1.0 / part_size;
182+ float fscale = 1.f, ifscale = 1.f / part_size;
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+
452195 if (!seg->tx[ch] || !seg->itx[ch])
453196 return AVERROR(ENOMEM);
454197 }
@@ -502,8 +245,7 @@ static void uninit_segment(AVFilterContext *ctx, AudioFIRSegment *seg) · 47 unmodified lines
502245 static int convert_coeffs(AVFilterContext *ctx)
503246 {
504247 AudioFIRContext *s = ctx->priv;
505− int ret, i, ch, n, cur_nb_taps;
506− float power = 0;
248+ int ret, i, cur_nb_taps;
507249
508250 if (!s->nb_taps) {
509251 int part_size, max_part_size;
@@ -546,109 +288,42 @@ static int convert_coeffs(AVFilterContext *ctx) · 36 unmodified lines
546288 return AVERROR_BUG;
547289 }
548290
549− if (s->response)
550− draw_response(ctx, s->video);
291+ if (s->response) {
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+ }
551301
552302 s->gain = 1;
553303 cur_nb_taps = s->ir[s->selir]->nb_samples;
554304
555− switch (s->gtype) {
556− case -1:
557− /* nothing to do */
305+ switch (s->format) {
306+ case AV_SAMPLE_FMT_FLTP:
307+ ret = get_power_float(ctx, s, cur_nb_taps);
558308 break;
559− case 0:
560− for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
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;
309+ case AV_SAMPLE_FMT_DBLP:
310+ ret = get_power_double(ctx, s, cur_nb_taps);
567311 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;
588312 }
589313
590− s->gain = FFMIN(s->gain * s->ir_gain, 1.f);
591− av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain);
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− }
314+ if (ret < 0)
315+ return ret;
597316
598317 av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", cur_nb_taps);
599318 av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments);
600319
601− for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
602− float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
603− int toffset = 0;
604−
605− for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++)
606− time[i] = 0;
607−
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− }
320+ switch (s->format) {
321+ case AV_SAMPLE_FMT_FLTP:
322+ convert_channels_float(ctx, s);
323+ break;
324+ case AV_SAMPLE_FMT_DBLP:
325+ convert_channels_double(ctx, s);
326+ break;
652327 }
653328
654329 s->have_coeffs = 1;
@@ -762,9 +437,10 @@ static int activate(AVFilterContext *ctx) · 107 unmodified lines
762437 static int query_formats(AVFilterContext *ctx)
763438 {
764439 AudioFIRContext *s = ctx->priv;
765− static const enum AVSampleFormat sample_fmts[] = {
766− AV_SAMPLE_FMT_FLTP,
767− AV_SAMPLE_FMT_NONE
440+ static const enum AVSampleFormat sample_fmts[3][3] = {
441+ { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE },
442+ { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE },
443+ { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE },
768444 };
769445 static const enum AVPixelFormat pix_fmts[] = {
770446 AV_PIX_FMT_RGB0,
@@ -801,7 +477,7 @@ static int query_formats(AVFilterContext *ctx) · 30 unmodified lines
801477 }
802478 }
803479
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)
805481 return ret;
806482
807483 return ff_set_common_all_samplerates(ctx);
@@ -827,6 +503,7 @@ FF_ENABLE_DEPRECATION_WARNINGS · 19 unmodified lines
827503
828504 s->nb_channels = outlink->ch_layout.nb_channels;
829505 s->nb_coef_channels = ctx->inputs[1 + s->selir]->ch_layout.nb_channels;
506+ s->format = outlink->format;
830507
831508 return 0;
832509 }
@@ -977,6 +654,10 @@ static const AVOption afir_options[] = { · 144 unmodified lines
977654 { "maxp", "set max partition size", OFFSET(maxp), AV_OPT_TYPE_INT, {.i64=8192}, 8, 32768, AF },
978655 { "nbirs", "set number of input IRs",OFFSET(nb_irs),AV_OPT_TYPE_INT, {.i64=1}, 1, 32, AF },
979656 { "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" },
980661 { NULL }
981662 };
982663
libavfilter/af_afir.h+99−0
@@ -0,0 +1,99 @@
1+/*
2+ * Copyright (c) 2017 Paul B Mahol
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+#ifndef AVFILTER_AFIR_H
22+#define AVFILTER_AFIR_H
23+
24+#include "libavutil/float_dsp.h"
25+#include "libavutil/frame.h"
26+#include "libavutil/rational.h"
27+#include "libavutil/tx.h"
28+#include "avfilter.h"
29+#include "af_afirdsp.h"
30+
31+typedef struct AudioFIRSegment {
32+ int nb_partitions;
33+ int part_size;
34+ int block_size;
35+ int fft_length;
36+ int coeff_size;
37+ int input_size;
38+ int input_offset;
39+
40+ int *output_offset;
41+ int *part_index;
42+
43+ AVFrame *sumin;
44+ AVFrame *sumout;
45+ AVFrame *blockin;
46+ AVFrame *blockout;
47+ AVFrame *buffer;
48+ AVFrame *coeff;
49+ AVFrame *input;
50+ AVFrame *output;
51+
52+ AVTXContext **tx, **itx;
53+ av_tx_fn tx_fn, itx_fn;
54+} AudioFIRSegment;
55+
56+typedef struct AudioFIRContext {
57+ const AVClass *class;
58+
59+ float wet_gain;
60+ float dry_gain;
61+ float length;
62+ int gtype;
63+ float ir_gain;
64+ int ir_format;
65+ float max_ir_len;
66+ int response;
67+ int w, h;
68+ AVRational frame_rate;
69+ int ir_channel;
70+ int minp;
71+ int maxp;
72+ int nb_irs;
73+ int selir;
74+ int precision;
75+ int format;
76+
77+ double gain;
78+
79+ int eof_coeffs[32];
80+ int have_coeffs;
81+ int nb_taps;
82+ int nb_channels;
83+ int nb_coef_channels;
84+ int one2many;
85+
86+ AudioFIRSegment seg[1024];
87+ int nb_segments;
88+
89+ AVFrame *in;
90+ AVFrame *ir[32];
91+ AVFrame *video;
92+ int min_part_size;
93+ int64_t pts;
94+
95+ AudioFIRDSPContext afirdsp;
96+ AVFloatDSPContext *fdsp;
97+} AudioFIRContext;
98+
99+#endif /* AVFILTER_AFIR_H */
libavfilter/af_afirdsp.h+20−0
@@ -29,6 +29,8 @@ · 28 unmodified lines
2929 typedef struct AudioFIRDSPContext {
3030 void (*fcmul_add)(float *sum, const float *t, const float *c,
3131 ptrdiff_t len);
32+ void (*dcmul_add)(double *sum, const double *t, const double *c,
33+ ptrdiff_t len);
3234 } AudioFIRDSPContext;
3335
3436 void ff_afir_init_x86(AudioFIRDSPContext *s);
@@ -50,9 +52,27 @@ static void fcmul_add_c(float *sum, const float *t, const float *c, ptrdiff_t le · 15 unmodified lines
5052 sum[2 * n] += t[2 * n] * c[2 * n];
5153 }
5254
55+static void dcmul_add_c(double *sum, const double *t, const double *c, ptrdiff_t len)
56+{
57+ int n;
58+
59+ for (n = 0; n < len; n++) {
60+ const double cre = c[2 * n ];
61+ const double cim = c[2 * n + 1];
62+ const double tre = t[2 * n ];
63+ const double tim = t[2 * n + 1];
64+
65+ sum[2 * n ] += tre * cre - tim * cim;
66+ sum[2 * n + 1] += tre * cim + tim * cre;
67+ }
68+
69+ sum[2 * n] += t[2 * n] * c[2 * n];
70+}
71+
5372 static av_unused void ff_afir_init(AudioFIRDSPContext *dsp)
5473 {
5574 dsp->fcmul_add = fcmul_add_c;
75+ dsp->dcmul_add = dcmul_add_c;
5676
5777 if (ARCH_X86)
5878 ff_afir_init_x86(dsp);
libavfilter/afir_template.c+392−0
@@ -0,0 +1,392 @@
1+/*
2+ * Copyright (c) 2017 Paul B Mahol
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+#include "avfilter.h"
22+#include "formats.h"
23+#include "internal.h"
24+#include "audio.h"
25+
26+#undef ctype
27+#undef ftype
28+#undef SQRT
29+#undef SAMPLE_FORMAT
30+#if DEPTH == 32
31+#define SAMPLE_FORMAT float
32+#define SQRT sqrtf
33+#define ctype AVComplexFloat
34+#define ftype float
35+#else
36+#define SAMPLE_FORMAT double
37+#define SQRT sqrt
38+#define ctype AVComplexDouble
39+#define ftype double
40+#endif
41+
42+#define fn3(a,b) a##_##b
43+#define fn2(a,b) fn3(a,b)
44+#define fn(a) fn2(a, SAMPLE_FORMAT)
45+
46+static void fn(draw_response)(AVFilterContext *ctx, AVFrame *out)
47+{
48+ AudioFIRContext *s = ctx->priv;
49+ ftype *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN;
50+ ftype min_delay = FLT_MAX, max_delay = FLT_MIN;
51+ int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1;
52+ char text[32];
53+ int channel, i, x;
54+
55+ memset(out->data[0], 0, s->h * out->linesize[0]);
56+
57+ phase = av_malloc_array(s->w, sizeof(*phase));
58+ mag = av_malloc_array(s->w, sizeof(*mag));
59+ delay = av_malloc_array(s->w, sizeof(*delay));
60+ if (!mag || !phase || !delay)
61+ goto end;
62+
63+ channel = av_clip(s->ir_channel, 0, s->ir[s->selir]->ch_layout.nb_channels - 1);
64+ for (i = 0; i < s->w; i++) {
65+ const ftype *src = (const ftype *)s->ir[s->selir]->extended_data[channel];
66+ double w = i * M_PI / (s->w - 1);
67+ double div, real_num = 0., imag_num = 0., real = 0., imag = 0.;
68+
69+ for (x = 0; x < s->nb_taps; x++) {
70+ real += cos(-x * w) * src[x];
71+ imag += sin(-x * w) * src[x];
72+ real_num += cos(-x * w) * src[x] * x;
73+ imag_num += sin(-x * w) * src[x] * x;
74+ }
75+
76+ mag[i] = hypot(real, imag);
77+ phase[i] = atan2(imag, real);
78+ div = real * real + imag * imag;
79+ delay[i] = (real_num * real + imag_num * imag) / div;
80+ min = fminf(min, mag[i]);
81+ max = fmaxf(max, mag[i]);
82+ min_delay = fminf(min_delay, delay[i]);
83+ max_delay = fmaxf(max_delay, delay[i]);
84+ }
85+
86+ for (i = 0; i < s->w; i++) {
87+ int ymag = mag[i] / max * (s->h - 1);
88+ int ydelay = (delay[i] - min_delay) / (max_delay - min_delay) * (s->h - 1);
89+ int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1);
90+
91+ ymag = s->h - 1 - av_clip(ymag, 0, s->h - 1);
92+ yphase = s->h - 1 - av_clip(yphase, 0, s->h - 1);
93+ ydelay = s->h - 1 - av_clip(ydelay, 0, s->h - 1);
94+
95+ if (prev_ymag < 0)
96+ prev_ymag = ymag;
97+ if (prev_yphase < 0)
98+ prev_yphase = yphase;
99+ if (prev_ydelay < 0)
100+ prev_ydelay = ydelay;
101+
102+ draw_line(out, i, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF);
103+ draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00);
104+ draw_line(out, i, ydelay, FFMAX(i - 1, 0), prev_ydelay, 0xFF00FFFF);
105+
106+ prev_ymag = ymag;
107+ prev_yphase = yphase;
108+ prev_ydelay = ydelay;
109+ }
110+
111+ if (s->w > 400 && s->h > 100) {
112+ drawtext(out, 2, 2, "Max Magnitude:", 0xDDDDDDDD);
113+ snprintf(text, sizeof(text), "%.2f", max);
114+ drawtext(out, 15 * 8 + 2, 2, text, 0xDDDDDDDD);
115+
116+ drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD);
117+ snprintf(text, sizeof(text), "%.2f", min);
118+ drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD);
119+
120+ drawtext(out, 2, 22, "Max Delay:", 0xDDDDDDDD);
121+ snprintf(text, sizeof(text), "%.2f", max_delay);
122+ drawtext(out, 11 * 8 + 2, 22, text, 0xDDDDDDDD);
123+
124+ drawtext(out, 2, 32, "Min Delay:", 0xDDDDDDDD);
125+ snprintf(text, sizeof(text), "%.2f", min_delay);
126+ drawtext(out, 11 * 8 + 2, 32, text, 0xDDDDDDDD);
127+ }
128+
129+end:
130+ av_free(delay);
131+ av_free(phase);
132+ av_free(mag);
133+}
134+
135+static void fn(convert_channels)(AVFilterContext *ctx, AudioFIRContext *s)
136+{
137+ for (int ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
138+ ftype *time = (ftype *)s->ir[s->selir]->extended_data[!s->one2many * ch];
139+ int toffset = 0;
140+
141+ for (int i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++)
142+ time[i] = 0;
143+
144+ av_log(ctx, AV_LOG_DEBUG, "channel: %d\n", ch);
145+
146+ for (int segment = 0; segment < s->nb_segments; segment++) {
147+ AudioFIRSegment *seg = &s->seg[segment];
148+ ftype *blockin = (ftype *)seg->blockin->extended_data[ch];
149+ ftype *blockout = (ftype *)seg->blockout->extended_data[ch];
150+ ctype *coeff = (ctype *)seg->coeff->extended_data[ch];
151+
152+ av_log(ctx, AV_LOG_DEBUG, "segment: %d\n", segment);
153+
154+ for (int i = 0; i < seg->nb_partitions; i++) {
155+ const int coffset = i * seg->coeff_size;
156+ const int remaining = s->nb_taps - toffset;
157+ const int size = remaining >= seg->part_size ? seg->part_size : remaining;
158+
159+ if (size < 8) {
160+ for (int n = 0; n < size; n++)
161+ coeff[coffset + n].re = time[toffset + n];
162+
163+ toffset += size;
164+ continue;
165+ }
166+
167+ memset(blockin, 0, sizeof(*blockin) * seg->fft_length);
168+ memcpy(blockin, time + toffset, size * sizeof(*blockin));
169+
170+ seg->tx_fn(seg->tx[0], blockout, blockin, sizeof(ftype));
171+
172+ for (int n = 0; n < seg->part_size + 1; n++) {
173+ coeff[coffset + n].re = blockout[2 * n];
174+ coeff[coffset + n].im = blockout[2 * n + 1];
175+ }
176+
177+ toffset += size;
178+ }
179+
180+ av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", seg->nb_partitions);
181+ av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", seg->part_size);
182+ av_log(ctx, AV_LOG_DEBUG, "block size: %d\n", seg->block_size);
183+ av_log(ctx, AV_LOG_DEBUG, "fft_length: %d\n", seg->fft_length);
184+ av_log(ctx, AV_LOG_DEBUG, "coeff_size: %d\n", seg->coeff_size);
185+ av_log(ctx, AV_LOG_DEBUG, "input_size: %d\n", seg->input_size);
186+ av_log(ctx, AV_LOG_DEBUG, "input_offset: %d\n", seg->input_offset);
187+ }
188+ }
189+}
190+
191+static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s, int cur_nb_taps)
192+{
193+ ftype power = 0;
194+ int ch;
195+
196+ switch (s->gtype) {
197+ case -1:
198+ /* nothing to do */
199+ break;
200+ case 0:
201+ for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
202+ ftype *time = (ftype *)s->ir[s->selir]->extended_data[!s->one2many * ch];
203+
204+ for (int i = 0; i < cur_nb_taps; i++)
205+ power += FFABS(time[i]);
206+ }
207+ s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power;
208+ break;
209+ case 1:
210+ for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
211+ ftype *time = (ftype *)s->ir[s->selir]->extended_data[!s->one2many * ch];
212+
213+ for (int i = 0; i < cur_nb_taps; i++)
214+ power += time[i];
215+ }
216+ s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power;
217+ break;
218+ case 2:
219+ for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
220+ ftype *time = (ftype *)s->ir[s->selir]->extended_data[!s->one2many * ch];
221+
222+ for (int i = 0; i < cur_nb_taps; i++)
223+ power += time[i] * time[i];
224+ }
225+ s->gain = SQRT(ch / power);
226+ break;
227+ default:
228+ return AVERROR_BUG;
229+ }
230+
231+ s->gain = FFMIN(s->gain * s->ir_gain, 1.);
232+
233+ av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain);
234+
235+ for (int ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
236+ ftype *time = (ftype *)s->ir[s->selir]->extended_data[!s->one2many * ch];
237+
238+#if DEPTH == 32
239+ s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(cur_nb_taps, 4));
240+#else
241+ s->fdsp->vector_dmul_scalar(time, time, s->gain, FFALIGN(cur_nb_taps, 8));
242+#endif
243+ }
244+
245+ return 0;
246+}
247+
248+static void fn(direct)(const ftype *in, const ctype *ir, int len, ftype *out)
249+{
250+ for (int n = 0; n < len; n++)
251+ for (int m = 0; m <= n; m++)
252+ out[n] += ir[m].re * in[n - m];
253+}
254+
255+static void fn(fir_fadd)(AudioFIRContext *s, ftype *dst, const ftype *src, int nb_samples)
256+{
257+ if ((nb_samples & 15) == 0 && nb_samples >= 16) {
258+#if DEPTH == 32
259+ s->fdsp->vector_fmac_scalar(dst, src, 1.f, nb_samples);
260+#else
261+ s->fdsp->vector_dmac_scalar(dst, src, 1.0, nb_samples);
262+#endif
263+ } else {
264+ for (int n = 0; n < nb_samples; n++)
265+ dst[n] += src[n];
266+ }
267+}
268+
269+static int fn(fir_quantum)(AVFilterContext *ctx, AVFrame *out, int ch, int offset)
270+{
271+ AudioFIRContext *s = ctx->priv;
272+ const ftype *in = (const ftype *)s->in->extended_data[ch] + offset;
273+ ftype *blockin, *blockout, *buf, *ptr = (ftype *)out->extended_data[ch] + offset;
274+ const int nb_samples = FFMIN(s->min_part_size, out->nb_samples - offset);
275+ int n, i, j;
276+
277+ for (int segment = 0; segment < s->nb_segments; segment++) {
278+ AudioFIRSegment *seg = &s->seg[segment];
279+ ftype *src = (ftype *)seg->input->extended_data[ch];
280+ ftype *dst = (ftype *)seg->output->extended_data[ch];
281+ ftype *sumin = (ftype *)seg->sumin->extended_data[ch];
282+ ftype *sumout = (ftype *)seg->sumout->extended_data[ch];
283+
284+ if (s->min_part_size >= 8) {
285+#if DEPTH == 32
286+ s->fdsp->vector_fmul_scalar(src + seg->input_offset, in, s->dry_gain, FFALIGN(nb_samples, 4));
287+#else
288+ s->fdsp->vector_dmul_scalar(src + seg->input_offset, in, s->dry_gain, FFALIGN(nb_samples, 8));
289+#endif
290+ emms_c();
291+ } else {
292+ for (n = 0; n < nb_samples; n++)
293+ src[seg->input_offset + n] = in[n] * s->dry_gain;
294+ }
295+
296+ seg->output_offset[ch] += s->min_part_size;
297+ if (seg->output_offset[ch] == seg->part_size) {
298+ seg->output_offset[ch] = 0;
299+ } else {
300+ memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src));
301+
302+ dst += seg->output_offset[ch];
303+ fn(fir_fadd)(s, ptr, dst, nb_samples);
304+ continue;
305+ }
306+
307+ if (seg->part_size < 8) {
308+ memset(dst, 0, sizeof(*dst) * seg->part_size * seg->nb_partitions);
309+
310+ j = seg->part_index[ch];
311+
312+ for (i = 0; i < seg->nb_partitions; i++) {
313+ const int coffset = j * seg->coeff_size;
314+ const ctype *coeff = (const ctype *)seg->coeff->extended_data[ch * !s->one2many] + coffset;
315+
316+ fn(direct)(src, coeff, nb_samples, dst);
317+
318+ if (j == 0)
319+ j = seg->nb_partitions;
320+ j--;
321+ }
322+
323+ seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions;
324+
325+ memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src));
326+
327+ for (n = 0; n < nb_samples; n++) {
328+ ptr[n] += dst[n];
329+ }
330+ continue;
331+ }
332+
333+ memset(sumin, 0, sizeof(*sumin) * seg->fft_length);
334+ blockin = (ftype *)seg->blockin->extended_data[ch] + seg->part_index[ch] * seg->block_size;
335+ blockout = (ftype *)seg->blockout->extended_data[ch] + seg->part_index[ch] * seg->block_size;
336+ memset(blockin + seg->part_size, 0, sizeof(*blockin) * (seg->fft_length - seg->part_size));
337+
338+ memcpy(blockin, src, sizeof(*src) * seg->part_size);
339+
340+ seg->tx_fn(seg->tx[ch], blockout, blockin, sizeof(ftype));
341+
342+ j = seg->part_index[ch];
343+
344+ for (i = 0; i < seg->nb_partitions; i++) {
345+ const int coffset = j * seg->coeff_size;
346+ const ftype *blockout = (const ftype *)seg->blockout->extended_data[ch] + i * seg->block_size;
347+ const ctype *coeff = (const ctype *)seg->coeff->extended_data[ch * !s->one2many] + coffset;
348+
349+#if DEPTH == 32
350+ s->afirdsp.fcmul_add(sumin, blockout, (const ftype *)coeff, seg->part_size);
351+#else
352+ s->afirdsp.dcmul_add(sumin, blockout, (const ftype *)coeff, seg->part_size);
353+#endif
354+
355+ if (j == 0)
356+ j = seg->nb_partitions;
357+ j--;
358+ }
359+
360+ seg->itx_fn(seg->itx[ch], sumout, sumin, sizeof(ftype));
361+
362+ buf = (ftype *)seg->buffer->extended_data[ch];
363+ fn(fir_fadd)(s, buf, sumout, seg->part_size);
364+
365+ memcpy(dst, buf, seg->part_size * sizeof(*dst));
366+
367+ buf = (ftype *)seg->buffer->extended_data[ch];
368+ memcpy(buf, sumout + seg->part_size, seg->part_size * sizeof(*buf));
369+
370+ seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions;
371+
372+ memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src));
373+
374+ fn(fir_fadd)(s, ptr, dst, nb_samples);
375+ }
376+
377+ if (s->min_part_size >= 8) {
378+#if DEPTH == 32
379+ s->fdsp->vector_fmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 4));
380+#else
381+ s->fdsp->vector_dmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 8));
382+#endif
383+ emms_c();
384+ } else {
385+ for (n = 0; n < nb_samples; n++)
386+ ptr[n] *= s->wet_gain;
387+ }
388+
389+ return 0;
390+}
391+
392+

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t