| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2002 Naoki Shibata | ||
| 3 | * Copyright (c) 2017 Paul B Mahol | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "libavutil/mem.h" | ||
| 23 | #include "libavutil/opt.h" | ||
| 24 | #include "libavutil/tx.h" | ||
| 25 | |||
| 26 | #include "audio.h" | ||
| 27 | #include "avfilter.h" | ||
| 28 | #include "filters.h" | ||
| 29 | |||
| 30 | #define NBANDS 17 | ||
| 31 | #define M 15 | ||
| 32 | |||
| 33 | typedef struct EqParameter { | ||
| 34 | float lower, upper, gain; | ||
| 35 | } EqParameter; | ||
| 36 | |||
| 37 | typedef struct SuperEqualizerContext { | ||
| 38 | const AVClass *class; | ||
| 39 | |||
| 40 | EqParameter params[NBANDS + 1]; | ||
| 41 | |||
| 42 | float gains[NBANDS + 1]; | ||
| 43 | |||
| 44 | float fact[M + 1]; | ||
| 45 | float aa; | ||
| 46 | float iza; | ||
| 47 | float *ires, *irest; | ||
| 48 | float *fsamples, *fsamples_out; | ||
| 49 | int winlen, tabsize; | ||
| 50 | |||
| 51 | AVFrame *in, *out; | ||
| 52 | AVTXContext *rdft, *irdft; | ||
| 53 | av_tx_fn tx_fn, itx_fn; | ||
| 54 | } SuperEqualizerContext; | ||
| 55 | |||
| 56 | static const float bands[] = { | ||
| 57 | 65.406392, 92.498606, 130.81278, 184.99721, 261.62557, 369.99442, 523.25113, 739.9884, 1046.5023, | ||
| 58 | 1479.9768, 2093.0045, 2959.9536, 4186.0091, 5919.9072, 8372.0181, 11839.814, 16744.036 | ||
| 59 | }; | ||
| 60 | |||
| 61 | ✗ | static float izero(SuperEqualizerContext *s, float x) | |
| 62 | { | ||
| 63 | ✗ | float ret = 1; | |
| 64 | int m; | ||
| 65 | |||
| 66 | ✗ | for (m = 1; m <= M; m++) { | |
| 67 | float t; | ||
| 68 | |||
| 69 | ✗ | t = pow(x / 2, m) / s->fact[m]; | |
| 70 | ✗ | ret += t*t; | |
| 71 | } | ||
| 72 | |||
| 73 | ✗ | return ret; | |
| 74 | } | ||
| 75 | |||
| 76 | ✗ | static float hn_lpf(int n, float f, float fs) | |
| 77 | { | ||
| 78 | ✗ | float t = 1 / fs; | |
| 79 | ✗ | float omega = 2 * M_PI * f; | |
| 80 | |||
| 81 | ✗ | if (n * omega * t == 0) | |
| 82 | ✗ | return 2 * f * t; | |
| 83 | ✗ | return 2 * f * t * sinf(n * omega * t) / (n * omega * t); | |
| 84 | } | ||
| 85 | |||
| 86 | ✗ | static float hn_imp(int n) | |
| 87 | { | ||
| 88 | ✗ | return n == 0 ? 1.f : 0.f; | |
| 89 | } | ||
| 90 | |||
| 91 | ✗ | static float hn(int n, EqParameter *param, float fs) | |
| 92 | { | ||
| 93 | float ret, lhn; | ||
| 94 | int i; | ||
| 95 | |||
| 96 | ✗ | lhn = hn_lpf(n, param[0].upper, fs); | |
| 97 | ✗ | ret = param[0].gain*lhn; | |
| 98 | |||
| 99 | ✗ | for (i = 1; i < NBANDS + 1 && param[i].upper < fs / 2; i++) { | |
| 100 | ✗ | float lhn2 = hn_lpf(n, param[i].upper, fs); | |
| 101 | ✗ | ret += param[i].gain * (lhn2 - lhn); | |
| 102 | ✗ | lhn = lhn2; | |
| 103 | } | ||
| 104 | |||
| 105 | ✗ | ret += param[i].gain * (hn_imp(n) - lhn); | |
| 106 | |||
| 107 | ✗ | return ret; | |
| 108 | } | ||
| 109 | |||
| 110 | ✗ | static float alpha(float a) | |
| 111 | { | ||
| 112 | ✗ | if (a <= 21) | |
| 113 | ✗ | return 0; | |
| 114 | ✗ | if (a <= 50) | |
| 115 | ✗ | return .5842f * pow(a - 21, 0.4f) + 0.07886f * (a - 21); | |
| 116 | ✗ | return .1102f * (a - 8.7f); | |
| 117 | } | ||
| 118 | |||
| 119 | ✗ | static float win(SuperEqualizerContext *s, float n, int N) | |
| 120 | { | ||
| 121 | ✗ | return izero(s, alpha(s->aa) * sqrtf(1 - 4 * n * n / ((N - 1) * (N - 1)))) / s->iza; | |
| 122 | } | ||
| 123 | |||
| 124 | ✗ | static void process_param(float *bc, EqParameter *param, float fs) | |
| 125 | { | ||
| 126 | int i; | ||
| 127 | |||
| 128 | ✗ | for (i = 0; i <= NBANDS; i++) { | |
| 129 | ✗ | param[i].lower = i == 0 ? 0 : bands[i - 1]; | |
| 130 | ✗ | param[i].upper = i == NBANDS ? fs : bands[i]; | |
| 131 | ✗ | param[i].gain = bc[i]; | |
| 132 | } | ||
| 133 | ✗ | } | |
| 134 | |||
| 135 | ✗ | static int equ_init(SuperEqualizerContext *s, int wb) | |
| 136 | { | ||
| 137 | ✗ | float scale = 1.f, iscale = 1.f; | |
| 138 | int i, j, ret; | ||
| 139 | |||
| 140 | ✗ | ret = av_tx_init(&s->rdft, &s->tx_fn, AV_TX_FLOAT_RDFT, 0, 1 << wb, &scale, 0); | |
| 141 | ✗ | if (ret < 0) | |
| 142 | ✗ | return ret; | |
| 143 | |||
| 144 | ✗ | ret = av_tx_init(&s->irdft, &s->itx_fn, AV_TX_FLOAT_RDFT, 1, 1 << wb, &iscale, 0); | |
| 145 | ✗ | if (ret < 0) | |
| 146 | ✗ | return ret; | |
| 147 | |||
| 148 | ✗ | s->aa = 96; | |
| 149 | ✗ | s->winlen = (1 << (wb-1))-1; | |
| 150 | ✗ | s->tabsize = 1 << wb; | |
| 151 | |||
| 152 | ✗ | s->ires = av_calloc(s->tabsize + 2, sizeof(float)); | |
| 153 | ✗ | s->irest = av_calloc(s->tabsize, sizeof(float)); | |
| 154 | ✗ | s->fsamples = av_calloc(s->tabsize, sizeof(float)); | |
| 155 | ✗ | s->fsamples_out = av_calloc(s->tabsize + 2, sizeof(float)); | |
| 156 | ✗ | if (!s->ires || !s->irest || !s->fsamples || !s->fsamples_out) | |
| 157 | ✗ | return AVERROR(ENOMEM); | |
| 158 | |||
| 159 | ✗ | for (i = 0; i <= M; i++) { | |
| 160 | ✗ | s->fact[i] = 1; | |
| 161 | ✗ | for (j = 1; j <= i; j++) | |
| 162 | ✗ | s->fact[i] *= j; | |
| 163 | } | ||
| 164 | |||
| 165 | ✗ | s->iza = izero(s, alpha(s->aa)); | |
| 166 | |||
| 167 | ✗ | return 0; | |
| 168 | } | ||
| 169 | |||
| 170 | ✗ | static void make_fir(SuperEqualizerContext *s, float *lbc, float *rbc, EqParameter *param, float fs) | |
| 171 | { | ||
| 172 | ✗ | const int winlen = s->winlen; | |
| 173 | ✗ | const int tabsize = s->tabsize; | |
| 174 | int i; | ||
| 175 | |||
| 176 | ✗ | if (fs <= 0) | |
| 177 | ✗ | return; | |
| 178 | |||
| 179 | ✗ | process_param(lbc, param, fs); | |
| 180 | ✗ | for (i = 0; i < winlen; i++) | |
| 181 | ✗ | s->irest[i] = hn(i - winlen / 2, param, fs) * win(s, i - winlen / 2, winlen); | |
| 182 | ✗ | for (; i < tabsize; i++) | |
| 183 | ✗ | s->irest[i] = 0; | |
| 184 | |||
| 185 | ✗ | s->tx_fn(s->rdft, s->ires, s->irest, sizeof(float)); | |
| 186 | } | ||
| 187 | |||
| 188 | ✗ | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
| 189 | { | ||
| 190 | ✗ | AVFilterContext *ctx = inlink->dst; | |
| 191 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 192 | ✗ | AVFilterLink *outlink = ctx->outputs[0]; | |
| 193 | ✗ | const float *ires = s->ires; | |
| 194 | ✗ | float *fsamples_out = s->fsamples_out; | |
| 195 | ✗ | float *fsamples = s->fsamples; | |
| 196 | int ch, i; | ||
| 197 | |||
| 198 | ✗ | AVFrame *out = ff_get_audio_buffer(outlink, in->nb_samples); | |
| 199 | float *src, *dst, *ptr; | ||
| 200 | |||
| 201 | ✗ | if (!out) { | |
| 202 | ✗ | av_frame_free(&in); | |
| 203 | ✗ | return AVERROR(ENOMEM); | |
| 204 | } | ||
| 205 | |||
| 206 | ✗ | for (ch = 0; ch < in->ch_layout.nb_channels; ch++) { | |
| 207 | ✗ | ptr = (float *)out->extended_data[ch]; | |
| 208 | ✗ | dst = (float *)s->out->extended_data[ch]; | |
| 209 | ✗ | src = (float *)in->extended_data[ch]; | |
| 210 | |||
| 211 | ✗ | for (i = 0; i < in->nb_samples; i++) | |
| 212 | ✗ | fsamples[i] = src[i]; | |
| 213 | ✗ | for (; i < s->tabsize; i++) | |
| 214 | ✗ | fsamples[i] = 0; | |
| 215 | |||
| 216 | ✗ | s->tx_fn(s->rdft, fsamples_out, fsamples, sizeof(float)); | |
| 217 | |||
| 218 | ✗ | for (i = 0; i <= s->tabsize / 2; i++) { | |
| 219 | float re, im; | ||
| 220 | |||
| 221 | ✗ | re = ires[i*2 ] * fsamples_out[i*2] - ires[i*2+1] * fsamples_out[i*2+1]; | |
| 222 | ✗ | im = ires[i*2+1] * fsamples_out[i*2] + ires[i*2 ] * fsamples_out[i*2+1]; | |
| 223 | |||
| 224 | ✗ | fsamples_out[i*2 ] = re; | |
| 225 | ✗ | fsamples_out[i*2+1] = im; | |
| 226 | } | ||
| 227 | |||
| 228 | ✗ | s->itx_fn(s->irdft, fsamples, fsamples_out, sizeof(AVComplexFloat)); | |
| 229 | |||
| 230 | ✗ | for (i = 0; i < s->winlen; i++) | |
| 231 | ✗ | dst[i] += fsamples[i] / s->tabsize; | |
| 232 | ✗ | for (i = s->winlen; i < s->tabsize; i++) | |
| 233 | ✗ | dst[i] = fsamples[i] / s->tabsize; | |
| 234 | ✗ | for (i = 0; i < out->nb_samples; i++) | |
| 235 | ✗ | ptr[i] = dst[i]; | |
| 236 | ✗ | for (i = 0; i < s->winlen; i++) | |
| 237 | ✗ | dst[i] = dst[i+s->winlen]; | |
| 238 | } | ||
| 239 | |||
| 240 | ✗ | out->pts = in->pts; | |
| 241 | ✗ | av_frame_free(&in); | |
| 242 | |||
| 243 | ✗ | return ff_filter_frame(outlink, out); | |
| 244 | } | ||
| 245 | |||
| 246 | ✗ | static int activate(AVFilterContext *ctx) | |
| 247 | { | ||
| 248 | ✗ | AVFilterLink *inlink = ctx->inputs[0]; | |
| 249 | ✗ | AVFilterLink *outlink = ctx->outputs[0]; | |
| 250 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 251 | ✗ | AVFrame *in = NULL; | |
| 252 | int ret; | ||
| 253 | |||
| 254 | ✗ | FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); | |
| 255 | |||
| 256 | ✗ | ret = ff_inlink_consume_samples(inlink, s->winlen, s->winlen, &in); | |
| 257 | ✗ | if (ret < 0) | |
| 258 | ✗ | return ret; | |
| 259 | ✗ | if (ret > 0) | |
| 260 | ✗ | return filter_frame(inlink, in); | |
| 261 | |||
| 262 | ✗ | FF_FILTER_FORWARD_STATUS(inlink, outlink); | |
| 263 | ✗ | FF_FILTER_FORWARD_WANTED(outlink, inlink); | |
| 264 | |||
| 265 | ✗ | return FFERROR_NOT_READY; | |
| 266 | } | ||
| 267 | |||
| 268 | ✗ | static av_cold int init(AVFilterContext *ctx) | |
| 269 | { | ||
| 270 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 271 | |||
| 272 | ✗ | return equ_init(s, 14); | |
| 273 | } | ||
| 274 | |||
| 275 | ✗ | static int config_input(AVFilterLink *inlink) | |
| 276 | { | ||
| 277 | ✗ | AVFilterContext *ctx = inlink->dst; | |
| 278 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 279 | |||
| 280 | ✗ | s->out = ff_get_audio_buffer(inlink, s->tabsize); | |
| 281 | ✗ | if (!s->out) | |
| 282 | ✗ | return AVERROR(ENOMEM); | |
| 283 | |||
| 284 | ✗ | return 0; | |
| 285 | } | ||
| 286 | |||
| 287 | ✗ | static int config_output(AVFilterLink *outlink) | |
| 288 | { | ||
| 289 | ✗ | AVFilterContext *ctx = outlink->src; | |
| 290 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 291 | |||
| 292 | ✗ | make_fir(s, s->gains, s->gains, s->params, outlink->sample_rate); | |
| 293 | |||
| 294 | ✗ | return 0; | |
| 295 | } | ||
| 296 | |||
| 297 | ✗ | static av_cold void uninit(AVFilterContext *ctx) | |
| 298 | { | ||
| 299 | ✗ | SuperEqualizerContext *s = ctx->priv; | |
| 300 | |||
| 301 | ✗ | av_frame_free(&s->out); | |
| 302 | ✗ | av_freep(&s->irest); | |
| 303 | ✗ | av_freep(&s->ires); | |
| 304 | ✗ | av_freep(&s->fsamples); | |
| 305 | ✗ | av_freep(&s->fsamples_out); | |
| 306 | ✗ | av_tx_uninit(&s->rdft); | |
| 307 | ✗ | av_tx_uninit(&s->irdft); | |
| 308 | ✗ | } | |
| 309 | |||
| 310 | static const AVFilterPad superequalizer_inputs[] = { | ||
| 311 | { | ||
| 312 | .name = "default", | ||
| 313 | .type = AVMEDIA_TYPE_AUDIO, | ||
| 314 | .config_props = config_input, | ||
| 315 | }, | ||
| 316 | }; | ||
| 317 | |||
| 318 | static const AVFilterPad superequalizer_outputs[] = { | ||
| 319 | { | ||
| 320 | .name = "default", | ||
| 321 | .type = AVMEDIA_TYPE_AUDIO, | ||
| 322 | .config_props = config_output, | ||
| 323 | }, | ||
| 324 | }; | ||
| 325 | |||
| 326 | #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||
| 327 | #define OFFSET(x) offsetof(SuperEqualizerContext, x) | ||
| 328 | |||
| 329 | static const AVOption superequalizer_options[] = { | ||
| 330 | { "1b", "set 65Hz band gain", OFFSET(gains [0]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 331 | { "2b", "set 92Hz band gain", OFFSET(gains [1]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 332 | { "3b", "set 131Hz band gain", OFFSET(gains [2]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 333 | { "4b", "set 185Hz band gain", OFFSET(gains [3]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 334 | { "5b", "set 262Hz band gain", OFFSET(gains [4]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 335 | { "6b", "set 370Hz band gain", OFFSET(gains [5]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 336 | { "7b", "set 523Hz band gain", OFFSET(gains [6]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 337 | { "8b", "set 740Hz band gain", OFFSET(gains [7]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 338 | { "9b", "set 1047Hz band gain", OFFSET(gains [8]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 339 | { "10b", "set 1480Hz band gain", OFFSET(gains [9]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 340 | { "11b", "set 2093Hz band gain", OFFSET(gains[10]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 341 | { "12b", "set 2960Hz band gain", OFFSET(gains[11]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 342 | { "13b", "set 4186Hz band gain", OFFSET(gains[12]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 343 | { "14b", "set 5920Hz band gain", OFFSET(gains[13]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 344 | { "15b", "set 8372Hz band gain", OFFSET(gains[14]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 345 | { "16b", "set 11840Hz band gain", OFFSET(gains[15]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 346 | { "17b", "set 16744Hz band gain", OFFSET(gains[16]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 347 | { "18b", "set 20000Hz band gain", OFFSET(gains[17]), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 20, AF }, | ||
| 348 | { NULL } | ||
| 349 | }; | ||
| 350 | |||
| 351 | AVFILTER_DEFINE_CLASS(superequalizer); | ||
| 352 | |||
| 353 | const FFFilter ff_af_superequalizer = { | ||
| 354 | .p.name = "superequalizer", | ||
| 355 | .p.description = NULL_IF_CONFIG_SMALL("Apply 18 band equalization filter."), | ||
| 356 | .p.priv_class = &superequalizer_class, | ||
| 357 | .priv_size = sizeof(SuperEqualizerContext), | ||
| 358 | .init = init, | ||
| 359 | .activate = activate, | ||
| 360 | .uninit = uninit, | ||
| 361 | FILTER_INPUTS(superequalizer_inputs), | ||
| 362 | FILTER_OUTPUTS(superequalizer_outputs), | ||
| 363 | FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), | ||
| 364 | }; | ||
| 365 |