History

avfilter/af_adynamicequalizer: rework processing

Paul B Mahol committed 4 years ago

Commit 5676b7c1 parent 94644342 files · +91 −130Browse files

Unified · Split

2 files
  1. doc/filters.texi +15 −13
  2. libavfilter/af_adynamicequalizer.c +76 −117
doc/filters.texi+15−13
@@ -897,25 +897,17 @@ Set the amount of milliseconds the signal from detection has to fall below the · 896 unmodified lines
897897 detection threshold before equalization ends.
898898 Default is 200. Allowed range is between 1 and 2000.
899899
900−@item knee
901−Curve the sharp knee around the detection threshold to calculate
902−equalization gain more softly.
903−Default is 1. Allowed range is between 0 and 8.
904−
905900 @item ratio
906901 Set the ratio by which the equalization gain is raised.
907−Default is 1. Allowed range is between 1 and 20.
902+Default is 1. Allowed range is between 0 and 30.
908903
909904 @item makeup
910−Set the makeup offset in dB by which the equalization gain is raised.
911−Default is 0. Allowed range is between 0 and 30.
905+Set the makeup offset by which the equalization gain is raised.
906+Default is 0. Allowed range is between 0 and 100.
912907
913908 @item range
914−Set the max allowed cut/boost amount in dB. Default is 0.
915−Allowed range is from 0 to 200.
916−
917−@item slew
918−Set the slew factor. Default is 1. Allowed range is from 1 to 200.
909+Set the max allowed cut/boost amount. Default is 50.
910+Allowed range is from 1 to 200.
919911
920912 @item mode
921913 Set the mode of filter operation, can be one of the following:
@@ -939,6 +931,16 @@ Set the type of target filter, can be one of the following: · 17 unmodified lines
939931 @item highshelf
940932 @end table
941933 Default type is @samp{bell}.
934+
935+@item direction
936+Set processing direction relative to threshold.
937+@table @samp
938+@item downward
939+Boost or cut if threshhold is higher than detected volume.
940+@item upward
941+Boost or cut if threshhold is lower than detected volume.
942+@end table
943+Default direction is @samp{downward}.
942944 @end table
943945
944946 @subsection Commands
libavfilter/af_adynamicequalizer.c+76−117
@@ -34,13 +34,12 @@ typedef struct AudioDynamicEqualizerContext { · 33 unmodified lines
3434 double ratio;
3535 double range;
3636 double makeup;
37− double knee;
38− double slew;
3937 double attack;
4038 double release;
4139 double attack_coef;
4240 double release_coef;
4341 int mode;
42+ int direction;
4443 int type;
4544
4645 AVFrame *state;
@@ -55,6 +54,12 @@ static int config_input(AVFilterLink *inlink) · 8 unmodified lines
5554 if (!s->state)
5655 return AVERROR(ENOMEM);
5756
57+ for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
58+ double *state = (double *)s->state->extended_data[ch];
59+
60+ state[4] = 1.;
61+ }
62+
5863 return 0;
5964 }
6065
@@ -71,69 +76,6 @@ static double get_svf(double in, double *m, double *a, double *b) · 10 unmodified lines
7176 return m[0] * v0 + m[1] * v1 + m[2] * v2;
7277 }
7378
74−static inline double from_dB(double x)
75−{
76− return exp(0.05 * x * M_LN10);
77−}
78−
79−static inline double to_dB(double x)
80−{
81− return 20. * log10(x);
82−}
83−
84−static inline double sqr(double x)
85−{
86− return x * x;
87−}
88−
89−static double get_gain(double in, double srate, double makeup,
90− double aattack, double iratio, double knee, double range,
91− double thresdb, double slewfactor, double *state,
92− double attack_coeff, double release_coeff, double nc)
93−{
94− double width = (6. * knee) + 0.01;
95− double cdb = 0.;
96− double Lgain = 1.;
97− double Lxg, Lxl, Lyg, Lyl, Ly1;
98− double checkwidth = 0.;
99− double slewwidth = 1.8;
100− int attslew = 0;
101−
102− Lyg = 0.;
103− Lxg = to_dB(fabs(in) + DBL_EPSILON);
104−
105− Lyg = Lxg + (iratio - 1.) * sqr(Lxg - thresdb + width * .5) / (2. * width);
106−
107− checkwidth = 2. * fabs(Lxg - thresdb);
108− if (2. * (Lxg - thresdb) < -width) {
109− Lyg = Lxg;
110− } else if (checkwidth <= width) {
111− Lyg = thresdb + (Lxg - thresdb) * iratio;
112− if (checkwidth <= slewwidth) {
113− if (Lyg >= state[2])
114− attslew = 1;
115− }
116− } else if (2. * (Lxg - thresdb) > width) {
117− Lyg = thresdb + (Lxg - thresdb) * iratio;
118− }
119−
120− attack_coeff = attslew ? aattack : attack_coeff;
121−
122− Lxl = Lxg - Lyg;
123−
124− Ly1 = fmax(Lxl, release_coeff * state[1] +(1. - release_coeff) * Lxl);
125− Lyl = attack_coeff * state[0] + (1. - attack_coeff) * Ly1;
126−
127− cdb = -Lyl;
128− Lgain = from_dB(nc * fmin(cdb - makeup, range));
129−
130− state[0] = Lyl;
131− state[1] = Ly1;
132− state[2] = Lyg;
133−
134− return Lgain;
135−}
136−
13779 typedef struct ThreadData {
13880 AVFrame *in, *out;
13981 } ThreadData;
@@ -146,25 +88,24 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 6 unmodified lines
14688 AVFrame *out = td->out;
14789 const double sample_rate = in->sample_rate;
14890 const double makeup = s->makeup;
149− const double iratio = 1. / s->ratio;
91+ const double ratio = s->ratio;
15092 const double range = s->range;
15193 const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5);
15294 const double tfrequency = fmin(s->tfrequency, sample_rate * 0.5);
153− const double threshold = to_dB(s->threshold + DBL_EPSILON);
95+ const double threshold = s->threshold;
15496 const double release = s->release_coef;
97+ const double irelease = 1. - release;
15598 const double attack = s->attack_coef;
99+ const double iattack = 1. - attack;
156100 const double dqfactor = s->dqfactor;
157101 const double tqfactor = s->tqfactor;
158102 const double fg = tan(M_PI * tfrequency / sample_rate);
159103 const double dg = tan(M_PI * dfrequency / sample_rate);
160104 const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
161105 const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
106+ const int direction = s->direction;
162107 const int mode = s->mode;
163108 const int type = s->type;
164− const double knee = s->knee;
165− const double slew = s->slew;
166− const double aattack = exp(-1000. / ((s->attack + 2.0 * (slew - 1.)) * sample_rate));
167− const double nc = mode == 0 ? 1. : -1.;
168109 double da[3], dm[3];
169110
170111 {
@@ -175,7 +116,7 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 4 unmodified lines
175116 da[2] = dg * da[1];
176117
177118 dm[0] = 0.;
178− dm[1] = 1.;
119+ dm[1] = k;
179120 dm[2] = 0.;
180121 }
181122
@@ -192,46 +133,63 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 10 unmodified lines
192133 detect = listen = get_svf(src[n], dm, da, state);
193134 detect = fabs(detect);
194135
195− gain = get_gain(detect, sample_rate, makeup,
196− aattack, iratio, knee, range, threshold, slew,
197− &state[4], attack, release, nc);
198−
199− switch (type) {
200− case 0:
201− k = 1. / (tqfactor * gain);
202−
203− fa[0] = 1. / (1. + fg * (fg + k));
204− fa[1] = fg * fa[0];
205− fa[2] = fg * fa[1];
206−
207− fm[0] = 1.;
208− fm[1] = k * (gain * gain - 1.);
209− fm[2] = 0.;
210− break;
211− case 1:
212− k = 1. / tqfactor;
213− g = fg / sqrt(gain);
214−
215− fa[0] = 1. / (1. + g * (g + k));
216− fa[1] = g * fa[0];
217− fa[2] = g * fa[1];
218−
219− fm[0] = 1.;
220− fm[1] = k * (gain - 1.);
221− fm[2] = gain * gain - 1.;
222− break;
223− case 2:
224− k = 1. / tqfactor;
225− g = fg / sqrt(gain);
226−
227− fa[0] = 1. / (1. + g * (g + k));
228− fa[1] = g * fa[0];
229− fa[2] = g * fa[1];
230−
231− fm[0] = gain * gain;
232− fm[1] = k * (1. - gain) * gain;
233− fm[2] = 1. - gain * gain;
234− break;
136+ if (direction == 0 && mode == 0 && detect < threshold)
137+ detect = 1. / av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
138+ else if (direction == 0 && mode == 1 && detect < threshold)
139+ detect = av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
140+ else if (direction == 1 && mode == 0 && detect > threshold)
141+ detect = 1. / av_clipd(1. + makeup + (detect - threshold) * ratio, 1., range);
142+ else if (direction == 1 && mode == 1 && detect > threshold)
143+ detect = av_clipd(1. + makeup + (detect - threshold) * ratio, 1., range);
144+ else
145+ detect = 1.;
146+
147+ if (detect < state[4]) {
148+ detect = iattack * detect + attack * state[4];
149+ } else {
150+ detect = irelease * detect + release * state[4];
151+ }
152+
153+ if (state[4] != detect || n == 0) {
154+ state[4] = gain = detect;
155+
156+ switch (type) {
157+ case 0:
158+ k = 1. / (tqfactor * gain);
159+
160+ fa[0] = 1. / (1. + fg * (fg + k));
161+ fa[1] = fg * fa[0];
162+ fa[2] = fg * fa[1];
163+
164+ fm[0] = 1.;
165+ fm[1] = k * (gain * gain - 1.);
166+ fm[2] = 0.;
167+ break;
168+ case 1:
169+ k = 1. / tqfactor;
170+ g = fg / sqrt(gain);
171+
172+ fa[0] = 1. / (1. + g * (g + k));
173+ fa[1] = g * fa[0];
174+ fa[2] = g * fa[1];
175+
176+ fm[0] = 1.;
177+ fm[1] = k * (gain - 1.);
178+ fm[2] = gain * gain - 1.;
179+ break;
180+ case 2:
181+ k = 1. / tqfactor;
182+ g = fg / sqrt(gain);
183+
184+ fa[0] = 1. / (1. + g * (g + k));
185+ fa[1] = g * fa[0];
186+ fa[2] = g * fa[1];
187+
188+ fm[0] = gain * gain;
189+ fm[1] = k * (1. - gain) * gain;
190+ fm[2] = 1. - gain * gain;
191+ break;
192+ }
235193 }
236194
237195 v = get_svf(src[n], fm, fa, &state[2]);
@@ -298,11 +256,9 @@ static const AVOption adynamicequalizer_options[] = { · 60 unmodified lines
298256 { "tqfactor", "set target Q factor", OFFSET(tqfactor), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.001, 1000, FLAGS },
299257 { "attack", "set attack duration", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 2000, FLAGS },
300258 { "release", "set release duration", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=200}, 1, 2000, FLAGS },
301− { "knee", "set knee factor", OFFSET(knee), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 8, FLAGS },
302− { "ratio", "set ratio factor", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 20, FLAGS },
303− { "makeup", "set makeup gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 30, FLAGS },
304− { "range", "set max gain", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 200, FLAGS },
305− { "slew", "set slew factor", OFFSET(slew), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 200, FLAGS },
259+ { "ratio", "set ratio factor", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 30, FLAGS },
260+ { "makeup", "set makeup gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 100, FLAGS },
261+ { "range", "set max gain", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 200, FLAGS },
306262 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, -1, 1, FLAGS, "mode" },
307263 { "listen", 0, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "mode" },
308264 { "cut", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
@@ -311,6 +267,9 @@ static const AVOption adynamicequalizer_options[] = { · 2 unmodified lines
311267 { "bell", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" },
312268 { "lowshelf", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" },
313269 { "highshelf",0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "type" },
270+ { "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "direction" },
271+ { "downward", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "direction" },
272+ { "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "direction" },
314273 { NULL }
315274 };
316275

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