History

avfilter/af_afir: add irnorm and irlink options

Deprecate gtype option.

Paul B Mahol committed 2 years ago

Commit 5452cbd1 parent 07c303b4 files · +91 −119Browse files

Unified · Split

4 files
  1. doc/filters.texi +14 −23
  2. libavfilter/af_afir.c +47 −10
  3. libavfilter/af_afir.h +3 −0
  4. libavfilter/afir_template.c +27 −86
doc/filters.texi+14−23
@@ -1794,33 +1794,24 @@ Set wet gain. This sets final output gain. · 1793 unmodified lines
1794Set Impulse Response filter length. Default is 1, which means whole IR is processed.1794Set Impulse Response filter length. Default is 1, which means whole IR is processed.
1795 1795
1796@item gtype1796@item gtype
1797Enable applying gain measured from power of IR.1797This option is deprecated, and does nothing.
1798 1798
1799Set which approach to use for auto gain measurement.1799@item irnorm
1800Set norm to be applied to IR coefficients before filtering.
1801Allowed range is from @var{-1} to @var{2}.
1802IR coefficients are normalized with calculated vector norm set by this option.
1803For negative values, no norm is calculated, and IR coefficients are not modified at all.
1804Default is @var{1}.
1800 1805
1801@table @option1806@item irlink
1802@item none1807For multichannel IR if this option is set to @var{true}. All IR channels will be
1803Do not apply any gain.1808normalized with maximal measured gain of all IR channels coefficients as set by @code{irnorm} option.
1804 1809When disabled, all IR coefficients in each IR channel will be normalized independently.
1805@item peak1810Default is @var{true}.
1806select peak gain, very conservative approach. This is default value.
1807
1808@item dc
1809select DC gain, limited application.
1810
1811@item gn
1812select gain to noise approach, this is most popular one.
1813
1814@item ac
1815select AC gain.
1816
1817@item rms
1818select RMS gain.
1819@end table
1820 1811
1821@item irgain1812@item irgain
1822Set gain to be applied to IR coefficients before filtering.1813Set gain to be applied to IR coefficients before filtering.
1823Allowed range is 0 to 1. This gain is applied after any gain applied with @var{gtype} option.1814Allowed range is 0 to 1. This gain is applied after any gain applied with @var{irnorm} option.
1824 1815
1825@item irfmt1816@item irfmt
1826Set format of IR stream. Can be @code{mono} or @code{input}.1817Set format of IR stream. Can be @code{mono} or @code{input}.
@@ -1899,7 +1890,7 @@ ffmpeg -i input.wav -i middle_tunnel_1way_mono.wav -lavfi afir output.wav · 72 unmodified lines
1899Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,1890Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,
1900the impulse response files are files with names l_ir.wav and r_ir.wav:1891the impulse response files are files with names l_ir.wav and r_ir.wav:
1901@example1892@example
1902"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:gtype=gn:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"1893"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
1903@end example1894@end example
1904@end itemize1895@end itemize
1905 1896
libavfilter/af_afir.c+47−10
@@ -393,6 +393,22 @@ skip: · 392 unmodified lines
393 393
394 switch (s->format) {394 switch (s->format) {
395 case AV_SAMPLE_FMT_FLTP:395 case AV_SAMPLE_FMT_FLTP:
396 for (int ch = 0; ch < s->nb_channels; ch++) {
397 const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
398
399 s->ch_gain[ch] = ir_gain_float(ctx, s, nb_taps, tsrc);
400 }
401
402 if (s->ir_link) {
403 float gain = +INFINITY;
404
405 for (int ch = 0; ch < s->nb_channels; ch++)
406 gain = fminf(gain, s->ch_gain[ch]);
407
408 for (int ch = 0; ch < s->nb_channels; ch++)
409 s->ch_gain[ch] = gain;
410 }
411
396 for (int ch = 0; ch < s->nb_channels; ch++) {412 for (int ch = 0; ch < s->nb_channels; ch++) {
397 const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];413 const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
398 float *time = (float *)s->norm_ir[selir]->extended_data[ch];414 float *time = (float *)s->norm_ir[selir]->extended_data[ch];
@@ -401,7 +417,7 @@ skip: · 2 unmodified lines
401 for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)417 for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
402 time[i] = 0;418 time[i] = 0;
403 419
404 get_power_float(ctx, s, nb_taps, ch, time);420 ir_scale_float(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
405 421
406 for (int n = 0; n < s->nb_segments[selir]; n++) {422 for (int n = 0; n < s->nb_segments[selir]; n++) {
407 AudioFIRSegment *seg = &s->seg[selir][n];423 AudioFIRSegment *seg = &s->seg[selir][n];
@@ -417,6 +433,22 @@ skip: · 9 unmodified lines
417 }433 }
418 break;434 break;
419 case AV_SAMPLE_FMT_DBLP:435 case AV_SAMPLE_FMT_DBLP:
436 for (int ch = 0; ch < s->nb_channels; ch++) {
437 const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
438
439 s->ch_gain[ch] = ir_gain_double(ctx, s, nb_taps, tsrc);
440 }
441
442 if (s->ir_link) {
443 double gain = +INFINITY;
444
445 for (int ch = 0; ch < s->nb_channels; ch++)
446 gain = fmin(gain, s->ch_gain[ch]);
447
448 for (int ch = 0; ch < s->nb_channels; ch++)
449 s->ch_gain[ch] = gain;
450 }
451
420 for (int ch = 0; ch < s->nb_channels; ch++) {452 for (int ch = 0; ch < s->nb_channels; ch++) {
421 const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];453 const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
422 double *time = (double *)s->norm_ir[selir]->extended_data[ch];454 double *time = (double *)s->norm_ir[selir]->extended_data[ch];
@@ -425,7 +457,8 @@ skip: · 2 unmodified lines
425 for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)457 for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
426 time[i] = 0;458 time[i] = 0;
427 459
428 get_power_double(ctx, s, nb_taps, ch, time);460 ir_scale_double(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
461
429 for (int n = 0; n < s->nb_segments[selir]; n++) {462 for (int n = 0; n < s->nb_segments[selir]; n++) {
430 AudioFIRSegment *seg = &s->seg[selir][n];463 AudioFIRSegment *seg = &s->seg[selir][n];
431 464
@@ -627,8 +660,9 @@ FF_ENABLE_DEPRECATION_WARNINGS · 195 unmodified lines
627 660
628 s->format = outlink->format;661 s->format = outlink->format;
629 s->nb_channels = outlink->ch_layout.nb_channels;662 s->nb_channels = outlink->ch_layout.nb_channels;
663 s->ch_gain = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->ch_gain));
630 s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));664 s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));
631 if (!s->loading)665 if (!s->loading || !s->ch_gain)
632 return AVERROR(ENOMEM);666 return AVERROR(ENOMEM);
633 667
634 s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);668 s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);
@@ -674,6 +708,7 @@ static av_cold void uninit(AVFilterContext *ctx) · 39 unmodified lines
674 AudioFIRContext *s = ctx->priv;708 AudioFIRContext *s = ctx->priv;
675 709
676 av_freep(&s->fdsp);710 av_freep(&s->fdsp);
711 av_freep(&s->ch_gain);
677 av_freep(&s->loading);712 av_freep(&s->loading);
678 713
679 for (int i = 0; i < s->nb_irs; i++) {714 for (int i = 0; i < s->nb_irs; i++) {
@@ -812,13 +847,15 @@ static const AVOption afir_options[] = { · 132 unmodified lines
812 { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },847 { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
813 { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },848 { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
814 { "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },849 { "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
815 { "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF, "gtype" },850 { "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
816 { "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF, "gtype" },851 { "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
817 { "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "gtype" },852 { "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
818 { "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "gtype" },853 { "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
819 { "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "gtype" },854 { "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
820 { "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "gtype" },855 { "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
821 { "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF, "gtype" },856 { "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
857 { "irnorm", "set IR norm", OFFSET(ir_norm), AV_OPT_TYPE_FLOAT, {.dbl=1}, -1, 2, AF },
858 { "irlink", "set IR link", OFFSET(ir_link), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AF },
822 { "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },859 { "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
823 { "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" },860 { "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" },
824 { "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" },861 { "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" },
libavfilter/af_afir.h+3−0
@@ -63,6 +63,8 @@ typedef struct AudioFIRContext { · 62 unmodified lines
63 float dry_gain;63 float dry_gain;
64 float length;64 float length;
65 int gtype;65 int gtype;
66 float ir_norm;
67 float ir_link;
66 float ir_gain;68 float ir_gain;
67 int ir_format;69 int ir_format;
68 int ir_load;70 int ir_load;
@@ -87,6 +89,7 @@ typedef struct AudioFIRContext { · 18 unmodified lines
87 int nb_channels;89 int nb_channels;
88 int one2many;90 int one2many;
89 int *loading;91 int *loading;
92 double *ch_gain;
90 93
91 AudioFIRSegment seg[MAX_IR_STREAMS][1024];94 AudioFIRSegment seg[MAX_IR_STREAMS][1024];
92 95
libavfilter/afir_template.c+27−86
@@ -29,6 +29,8 @@ · 28 unmodified lines
29#undef HYPOT29#undef HYPOT
30#undef SAMPLE_FORMAT30#undef SAMPLE_FORMAT
31#undef TX_TYPE31#undef TX_TYPE
32#undef FABS
33#undef POW
32#if DEPTH == 3234#if DEPTH == 32
33#define SAMPLE_FORMAT float35#define SAMPLE_FORMAT float
34#define SQRT sqrtf36#define SQRT sqrtf
@@ -36,6 +38,8 @@ · 1 unmodified line
36#define ctype AVComplexFloat38#define ctype AVComplexFloat
37#define ftype float39#define ftype float
38#define TX_TYPE AV_TX_FLOAT_RDFT40#define TX_TYPE AV_TX_FLOAT_RDFT
41#define FABS fabsf
42#define POW powf
39#else43#else
40#define SAMPLE_FORMAT double44#define SAMPLE_FORMAT double
41#define SQRT sqrt45#define SQRT sqrt
@@ -43,6 +47,8 @@ · 1 unmodified line
43#define ctype AVComplexDouble47#define ctype AVComplexDouble
44#define ftype double48#define ftype double
45#define TX_TYPE AV_TX_DOUBLE_RDFT49#define TX_TYPE AV_TX_DOUBLE_RDFT
50#define FABS fabs
51#define POW pow
46#endif52#endif
47 53
48#define fn3(a,b) a##_##b54#define fn3(a,b) a##_##b
@@ -139,95 +145,32 @@ end: · 90 unmodified lines
139 av_free(mag);145 av_free(mag);
140}146}
141 147
142static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,148static ftype fn(ir_gain)(AVFilterContext *ctx, AudioFIRContext *s,
143 int cur_nb_taps, int ch,149 int cur_nb_taps, const ftype *time)
144 ftype *time)
145{150{
146 ftype ch_gain = 1;151 ftype ch_gain, sum = 0;
147 152
148 switch (s->gtype) {153 if (s->ir_norm < 0.f) {
149 case -1:
150 ch_gain = 1;154 ch_gain = 1;
151 break;155 } else if (s->ir_norm == 0.f) {
152 case 0:156 for (int i = 0; i < cur_nb_taps; i++)
153 {157 sum += time[i];
154 ftype sum = 0;158 ch_gain = 1. / sum;
155 159 } else {
156 for (int i = 0; i < cur_nb_taps; i++)160 ftype ir_norm = s->ir_norm;
157 sum += FFABS(time[i]);161
158 ch_gain = 1. / sum;162 for (int i = 0; i < cur_nb_taps; i++)
159 }163 sum += POW(FABS(time[i]), ir_norm);
160 break;164 ch_gain = 1. / POW(sum, 1. / ir_norm);
161 case 1:
162 {
163 ftype sum = 0;
164
165 for (int i = 0; i < cur_nb_taps; i++)
166 sum += time[i];
167 ch_gain = 1. / sum;
168 }
169 break;
170 case 2:
171 {
172 ftype sum = 0;
173
174 for (int i = 0; i < cur_nb_taps; i++)
175 sum += time[i] * time[i];
176 ch_gain = 1. / SQRT(sum);
177 }
178 break;
179 case 3:
180 case 4:
181 {
182 ftype *inc, *outc, scale, power;
183 AVTXContext *tx;
184 av_tx_fn tx_fn;
185 int ret, size;
186
187 size = 1 << av_ceil_log2_c(cur_nb_taps);
188 inc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
189 outc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
190 if (!inc || !outc) {
191 av_free(outc);
192 av_free(inc);
193 break;
194 }
195
196 scale = 1.;
197 ret = av_tx_init(&tx, &tx_fn, TX_TYPE, 0, size, &scale, 0);
198 if (ret < 0) {
199 av_free(outc);
200 av_free(inc);
201 break;
202 }
203
204 {
205 memcpy(inc, time, cur_nb_taps * sizeof(SAMPLE_FORMAT));
206 tx_fn(tx, outc, inc, sizeof(SAMPLE_FORMAT));
207
208 power = 0;
209 if (s->gtype == 3) {
210 for (int i = 0; i < size / 2 + 1; i++)
211 power = FFMAX(power, HYPOT(outc[i * 2], outc[i * 2 + 1]));
212 } else {
213 ftype sum = 0;
214 for (int i = 0; i < size / 2 + 1; i++)
215 sum += HYPOT(outc[i * 2], outc[i * 2 + 1]);
216 power = SQRT(sum / (size / 2 + 1));
217 }
218
219 ch_gain = 1. / power;
220 }
221
222 av_tx_uninit(&tx);
223 av_free(outc);
224 av_free(inc);
225 }
226 break;
227 default:
228 return AVERROR_BUG;
229 }165 }
230 166
167 return ch_gain;
168}
169
170static void fn(ir_scale)(AVFilterContext *ctx, AudioFIRContext *s,
171 int cur_nb_taps, int ch,
172 ftype *time, ftype ch_gain)
173{
231 if (ch_gain != 1. || s->ir_gain != 1.) {174 if (ch_gain != 1. || s->ir_gain != 1.) {
232 ftype gain = ch_gain * s->ir_gain;175 ftype gain = ch_gain * s->ir_gain;
233 176
@@ -238,8 +181,6 @@ static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s, · 4 unmodified lines
238 s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));181 s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));
239#endif182#endif
240 }183 }
241
242 return 0;
243}184}
244 185
245static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,186static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,

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