| @@ -34,13 +34,12 @@ typedef struct AudioDynamicEqualizerContext { · 33 unmodified lines |
| 34 | 34 | double ratio; |
| 35 | 35 | double range; |
| 36 | 36 | double makeup; |
| 37 | | − double knee; |
| 38 | | − double slew; |
| 39 | 37 | double attack; |
| 40 | 38 | double release; |
| 41 | 39 | double attack_coef; |
| 42 | 40 | double release_coef; |
| 43 | 41 | int mode; |
| 42 | + int direction; |
| 44 | 43 | int type; |
| 45 | 44 | |
| 46 | 45 | AVFrame *state; |
| @@ -55,6 +54,12 @@ static int config_input(AVFilterLink *inlink) · 8 unmodified lines |
| 55 | 54 | if (!s->state) |
| 56 | 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 | 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 | 76 | return m[0] * v0 + m[1] * v1 + m[2] * v2; |
| 72 | 77 | } |
| 73 | 78 | |
| 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 | | − |
| 137 | 79 | typedef struct ThreadData { |
| 138 | 80 | AVFrame *in, *out; |
| 139 | 81 | } ThreadData; |
| @@ -146,25 +88,24 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 6 unmodified lines |
| 146 | 88 | AVFrame *out = td->out; |
| 147 | 89 | const double sample_rate = in->sample_rate; |
| 148 | 90 | const double makeup = s->makeup; |
| 149 | | − const double iratio = 1. / s->ratio; |
| 91 | + const double ratio = s->ratio; |
| 150 | 92 | const double range = s->range; |
| 151 | 93 | const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5); |
| 152 | 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 | 96 | const double release = s->release_coef; |
| 97 | + const double irelease = 1. - release; |
| 155 | 98 | const double attack = s->attack_coef; |
| 99 | + const double iattack = 1. - attack; |
| 156 | 100 | const double dqfactor = s->dqfactor; |
| 157 | 101 | const double tqfactor = s->tqfactor; |
| 158 | 102 | const double fg = tan(M_PI * tfrequency / sample_rate); |
| 159 | 103 | const double dg = tan(M_PI * dfrequency / sample_rate); |
| 160 | 104 | const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs; |
| 161 | 105 | const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; |
| 106 | + const int direction = s->direction; |
| 162 | 107 | const int mode = s->mode; |
| 163 | 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 | 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 | 116 | da[2] = dg * da[1]; |
| 176 | 117 | |
| 177 | 118 | dm[0] = 0.; |
| 178 | | − dm[1] = 1.; |
| 119 | + dm[1] = k; |
| 179 | 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 | 133 | detect = listen = get_svf(src[n], dm, da, state); |
| 193 | 134 | detect = fabs(detect); |
| 194 | 135 | |
| 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 | + } |
| 235 | 193 | } |
| 236 | 194 | |
| 237 | 195 | v = get_svf(src[n], fm, fa, &state[2]); |
| @@ -298,11 +256,9 @@ static const AVOption adynamicequalizer_options[] = { · 60 unmodified lines |
| 298 | 256 | { "tqfactor", "set target Q factor", OFFSET(tqfactor), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.001, 1000, FLAGS }, |
| 299 | 257 | { "attack", "set attack duration", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 2000, FLAGS }, |
| 300 | 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 }, |
| 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 }, |
| 306 | 262 | { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, -1, 1, FLAGS, "mode" }, |
| 307 | 263 | { "listen", 0, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "mode" }, |
| 308 | 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 | 267 | { "bell", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" }, |
| 312 | 268 | { "lowshelf", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" }, |
| 313 | 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 | 273 | { NULL } |
| 315 | 274 | }; |
| 316 | 275 | |