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
897detection threshold before equalization ends.897detection threshold before equalization ends.
898Default is 200. Allowed range is between 1 and 2000.898Default is 200. Allowed range is between 1 and 2000.
899 899
900@item knee
901Curve the sharp knee around the detection threshold to calculate
902equalization gain more softly.
903Default is 1. Allowed range is between 0 and 8.
904
905@item ratio900@item ratio
906Set the ratio by which the equalization gain is raised.901Set the ratio by which the equalization gain is raised.
907Default is 1. Allowed range is between 1 and 20.902Default is 1. Allowed range is between 0 and 30.
908 903
909@item makeup904@item makeup
910Set the makeup offset in dB by which the equalization gain is raised.905Set the makeup offset by which the equalization gain is raised.
911Default is 0. Allowed range is between 0 and 30.906Default is 0. Allowed range is between 0 and 100.
912 907
913@item range908@item range
914Set the max allowed cut/boost amount in dB. Default is 0.909Set the max allowed cut/boost amount. Default is 50.
915Allowed range is from 0 to 200.910Allowed range is from 1 to 200.
916
917@item slew
918Set the slew factor. Default is 1. Allowed range is from 1 to 200.
919 911
920@item mode912@item mode
921Set the mode of filter operation, can be one of the following:913Set 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
939@item highshelf931@item highshelf
940@end table932@end table
941Default type is @samp{bell}.933Default type is @samp{bell}.
934
935@item direction
936Set processing direction relative to threshold.
937@table @samp
938@item downward
939Boost or cut if threshhold is higher than detected volume.
940@item upward
941Boost or cut if threshhold is lower than detected volume.
942@end table
943Default direction is @samp{downward}.
942@end table944@end table
943 945
944@subsection Commands946@subsection Commands
libavfilter/af_adynamicequalizer.c+76−117
@@ -34,13 +34,12 @@ typedef struct AudioDynamicEqualizerContext { · 33 unmodified lines
34 double ratio;34 double ratio;
35 double range;35 double range;
36 double makeup;36 double makeup;
37 double knee;
38 double slew;
39 double attack;37 double attack;
40 double release;38 double release;
41 double attack_coef;39 double attack_coef;
42 double release_coef;40 double release_coef;
43 int mode;41 int mode;
42 int direction;
44 int type;43 int type;
45 44
46 AVFrame *state;45 AVFrame *state;
@@ -55,6 +54,12 @@ static int config_input(AVFilterLink *inlink) · 8 unmodified lines
55 if (!s->state)54 if (!s->state)
56 return AVERROR(ENOMEM);55 return AVERROR(ENOMEM);
57 56
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
58 return 0;63 return 0;
59}64}
60 65
@@ -71,69 +76,6 @@ static double get_svf(double in, double *m, double *a, double *b) · 10 unmodified lines
71 return m[0] * v0 + m[1] * v1 + m[2] * v2;76 return m[0] * v0 + m[1] * v1 + m[2] * v2;
72}77}
73 78
74static inline double from_dB(double x)
75{
76 return exp(0.05 * x * M_LN10);
77}
78
79static inline double to_dB(double x)
80{
81 return 20. * log10(x);
82}
83
84static inline double sqr(double x)
85{
86 return x * x;
87}
88
89static 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
137typedef struct ThreadData {79typedef struct ThreadData {
138 AVFrame *in, *out;80 AVFrame *in, *out;
139} ThreadData;81} ThreadData;
@@ -146,25 +88,24 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 6 unmodified lines
146 AVFrame *out = td->out;88 AVFrame *out = td->out;
147 const double sample_rate = in->sample_rate;89 const double sample_rate = in->sample_rate;
148 const double makeup = s->makeup;90 const double makeup = s->makeup;
149 const double iratio = 1. / s->ratio;91 const double ratio = s->ratio;
150 const double range = s->range;92 const double range = s->range;
151 const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5);93 const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5);
152 const double tfrequency = fmin(s->tfrequency, sample_rate * 0.5);94 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;
154 const double release = s->release_coef;96 const double release = s->release_coef;
97 const double irelease = 1. - release;
155 const double attack = s->attack_coef;98 const double attack = s->attack_coef;
99 const double iattack = 1. - attack;
156 const double dqfactor = s->dqfactor;100 const double dqfactor = s->dqfactor;
157 const double tqfactor = s->tqfactor;101 const double tqfactor = s->tqfactor;
158 const double fg = tan(M_PI * tfrequency / sample_rate);102 const double fg = tan(M_PI * tfrequency / sample_rate);
159 const double dg = tan(M_PI * dfrequency / sample_rate);103 const double dg = tan(M_PI * dfrequency / sample_rate);
160 const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;104 const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
161 const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;105 const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
106 const int direction = s->direction;
162 const int mode = s->mode;107 const int mode = s->mode;
163 const int type = s->type;108 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.;
168 double da[3], dm[3];109 double da[3], dm[3];
169 110
170 {111 {
@@ -175,7 +116,7 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 4 unmodified lines
175 da[2] = dg * da[1];116 da[2] = dg * da[1];
176 117
177 dm[0] = 0.;118 dm[0] = 0.;
178 dm[1] = 1.;119 dm[1] = k;
179 dm[2] = 0.;120 dm[2] = 0.;
180 }121 }
181 122
@@ -192,46 +133,63 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 10 unmodified lines
192 detect = listen = get_svf(src[n], dm, da, state);133 detect = listen = get_svf(src[n], dm, da, state);
193 detect = fabs(detect);134 detect = fabs(detect);
194 135
195 gain = get_gain(detect, sample_rate, makeup,136 if (direction == 0 && mode == 0 && detect < threshold)
196 aattack, iratio, knee, range, threshold, slew,137 detect = 1. / av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
197 &state[4], attack, release, nc);138 else if (direction == 0 && mode == 1 && detect < threshold)
198 139 detect = av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
199 switch (type) {140 else if (direction == 1 && mode == 0 && detect > threshold)
200 case 0:141 detect = 1. / av_clipd(1. + makeup + (detect - threshold) * ratio, 1., range);
201 k = 1. / (tqfactor * gain);142 else if (direction == 1 && mode == 1 && detect > threshold)
202 143 detect = av_clipd(1. + makeup + (detect - threshold) * ratio, 1., range);
203 fa[0] = 1. / (1. + fg * (fg + k));144 else
204 fa[1] = fg * fa[0];145 detect = 1.;
205 fa[2] = fg * fa[1];146
206 147 if (detect < state[4]) {
207 fm[0] = 1.;148 detect = iattack * detect + attack * state[4];
208 fm[1] = k * (gain * gain - 1.);149 } else {
209 fm[2] = 0.;150 detect = irelease * detect + release * state[4];
210 break;151 }
211 case 1:152
212 k = 1. / tqfactor;153 if (state[4] != detect || n == 0) {
213 g = fg / sqrt(gain);154 state[4] = gain = detect;
214 155
215 fa[0] = 1. / (1. + g * (g + k));156 switch (type) {
216 fa[1] = g * fa[0];157 case 0:
217 fa[2] = g * fa[1];158 k = 1. / (tqfactor * gain);
218 159
219 fm[0] = 1.;160 fa[0] = 1. / (1. + fg * (fg + k));
220 fm[1] = k * (gain - 1.);161 fa[1] = fg * fa[0];
221 fm[2] = gain * gain - 1.;162 fa[2] = fg * fa[1];
222 break;163
223 case 2:164 fm[0] = 1.;
224 k = 1. / tqfactor;165 fm[1] = k * (gain * gain - 1.);
225 g = fg / sqrt(gain);166 fm[2] = 0.;
226 167 break;
227 fa[0] = 1. / (1. + g * (g + k));168 case 1:
228 fa[1] = g * fa[0];169 k = 1. / tqfactor;
229 fa[2] = g * fa[1];170 g = fg / sqrt(gain);
230 171
231 fm[0] = gain * gain;172 fa[0] = 1. / (1. + g * (g + k));
232 fm[1] = k * (1. - gain) * gain;173 fa[1] = g * fa[0];
233 fm[2] = 1. - gain * gain;174 fa[2] = g * fa[1];
234 break;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 }
235 }193 }
236 194
237 v = get_svf(src[n], fm, fa, &state[2]);195 v = get_svf(src[n], fm, fa, &state[2]);
@@ -298,11 +256,9 @@ static const AVOption adynamicequalizer_options[] = { · 60 unmodified lines
298 { "tqfactor", "set target Q factor", OFFSET(tqfactor), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.001, 1000, FLAGS },256 { "tqfactor", "set target Q factor", OFFSET(tqfactor), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.001, 1000, FLAGS },
299 { "attack", "set attack duration", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 2000, FLAGS },257 { "attack", "set attack duration", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 2000, FLAGS },
300 { "release", "set release duration", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=200}, 1, 2000, FLAGS },258 { "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 },259 { "ratio", "set ratio factor", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 30, FLAGS },
302 { "ratio", "set ratio factor", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 20, FLAGS },260 { "makeup", "set makeup gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 100, FLAGS },
303 { "makeup", "set makeup gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 30, FLAGS },261 { "range", "set max gain", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 200, 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 },
306 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, -1, 1, FLAGS, "mode" },262 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, -1, 1, FLAGS, "mode" },
307 { "listen", 0, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "mode" },263 { "listen", 0, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "mode" },
308 { "cut", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },264 { "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
311 { "bell", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" },267 { "bell", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" },
312 { "lowshelf", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" },268 { "lowshelf", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" },
313 { "highshelf",0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "type" },269 { "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" },
314 { NULL }273 { NULL }
315};274};
316 275

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