avfilter/af_adynamicequalizer: add auto option
This commit is contained in:
parent
6869a80e76
commit
40512dbd96
@ -1034,11 +1034,27 @@ Default type is @samp{bell}.
|
|||||||
Set processing direction relative to threshold.
|
Set processing direction relative to threshold.
|
||||||
@table @samp
|
@table @samp
|
||||||
@item downward
|
@item downward
|
||||||
Boost or cut if threshhold is higher than detected volume.
|
Boost/Cut if threshold is higher/lower than detected volume.
|
||||||
@item upward
|
@item upward
|
||||||
Boost or cut if threshhold is lower than detected volume.
|
Boost/Cut if threshold is lower/higher than detected volume.
|
||||||
@end table
|
@end table
|
||||||
Default direction is @samp{downward}.
|
Default direction is @samp{downward}.
|
||||||
|
|
||||||
|
@item auto
|
||||||
|
Automatically gather threshold from detection filter. By default
|
||||||
|
is @samp{disabled}.
|
||||||
|
This option is useful to detect threshold in certain time frame of
|
||||||
|
input audio stream, in such case option value is changed at runtime.
|
||||||
|
|
||||||
|
Available values are:
|
||||||
|
@table @samp
|
||||||
|
@item disabled
|
||||||
|
Disable using automatically gathered threshold value.
|
||||||
|
@item off
|
||||||
|
Stop picking threshold value.
|
||||||
|
@item on
|
||||||
|
Start picking threshold value.
|
||||||
|
@end table
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@subsection Commands
|
@subsection Commands
|
||||||
|
@ -40,6 +40,7 @@ typedef struct AudioDynamicEqualizerContext {
|
|||||||
double release_coef;
|
double release_coef;
|
||||||
int mode;
|
int mode;
|
||||||
int direction;
|
int direction;
|
||||||
|
int detection;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
AVFrame *state;
|
AVFrame *state;
|
||||||
@ -92,7 +93,6 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
const double range = s->range;
|
const double range = s->range;
|
||||||
const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5);
|
const double dfrequency = fmin(s->dfrequency, sample_rate * 0.5);
|
||||||
const double tfrequency = fmin(s->tfrequency, sample_rate * 0.5);
|
const double tfrequency = fmin(s->tfrequency, sample_rate * 0.5);
|
||||||
const double threshold = s->threshold;
|
|
||||||
const double release = s->release_coef;
|
const double release = s->release_coef;
|
||||||
const double irelease = 1. - release;
|
const double irelease = 1. - release;
|
||||||
const double attack = s->attack_coef;
|
const double attack = s->attack_coef;
|
||||||
@ -103,6 +103,7 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
const double dg = tan(M_PI * dfrequency / sample_rate);
|
const double dg = tan(M_PI * dfrequency / sample_rate);
|
||||||
const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
|
const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
|
||||||
const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
|
const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
|
||||||
|
const int detection = s->detection;
|
||||||
const int direction = s->direction;
|
const int direction = s->direction;
|
||||||
const int mode = s->mode;
|
const int mode = s->mode;
|
||||||
const int type = s->type;
|
const int type = s->type;
|
||||||
@ -124,6 +125,10 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
const double *src = (const double *)in->extended_data[ch];
|
const double *src = (const double *)in->extended_data[ch];
|
||||||
double *dst = (double *)out->extended_data[ch];
|
double *dst = (double *)out->extended_data[ch];
|
||||||
double *state = (double *)s->state->extended_data[ch];
|
double *state = (double *)s->state->extended_data[ch];
|
||||||
|
const double threshold = detection == 0 ? state[5] : s->threshold;
|
||||||
|
|
||||||
|
if (detection < 0)
|
||||||
|
state[5] = threshold;
|
||||||
|
|
||||||
for (int n = 0; n < out->nb_samples; n++) {
|
for (int n = 0; n < out->nb_samples; n++) {
|
||||||
double detect, gain, v, listen;
|
double detect, gain, v, listen;
|
||||||
@ -133,6 +138,9 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
detect = listen = get_svf(src[n], dm, da, state);
|
detect = listen = get_svf(src[n], dm, da, state);
|
||||||
detect = fabs(detect);
|
detect = fabs(detect);
|
||||||
|
|
||||||
|
if (detection > 0)
|
||||||
|
state[5] = fmax(state[5], detect);
|
||||||
|
|
||||||
if (direction == 0 && mode == 0 && detect < threshold)
|
if (direction == 0 && mode == 0 && detect < threshold)
|
||||||
detect = 1. / av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
|
detect = 1. / av_clipd(1. + makeup + (threshold - detect) * ratio, 1., range);
|
||||||
else if (direction == 0 && mode == 1 && detect < threshold)
|
else if (direction == 0 && mode == 1 && detect < threshold)
|
||||||
@ -144,11 +152,19 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
else
|
else
|
||||||
detect = 1.;
|
detect = 1.;
|
||||||
|
|
||||||
|
if (direction == 0) {
|
||||||
|
if (detect > state[4]) {
|
||||||
|
detect = iattack * detect + attack * state[4];
|
||||||
|
} else {
|
||||||
|
detect = irelease * detect + release * state[4];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (detect < state[4]) {
|
if (detect < state[4]) {
|
||||||
detect = iattack * detect + attack * state[4];
|
detect = iattack * detect + attack * state[4];
|
||||||
} else {
|
} else {
|
||||||
detect = irelease * detect + release * state[4];
|
detect = irelease * detect + release * state[4];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state[4] != detect || n == 0) {
|
if (state[4] != detect || n == 0) {
|
||||||
state[4] = gain = detect;
|
state[4] = gain = detect;
|
||||||
@ -270,6 +286,10 @@ static const AVOption adynamicequalizer_options[] = {
|
|||||||
{ "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "direction" },
|
{ "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "direction" },
|
||||||
{ "downward", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "direction" },
|
{ "downward", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "direction" },
|
||||||
{ "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "direction" },
|
{ "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "direction" },
|
||||||
|
{ "auto", "set auto threshold", OFFSET(detection), AV_OPT_TYPE_INT, {.i64=-1}, -1, 1, FLAGS, "auto" },
|
||||||
|
{ "disabled", 0, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "auto" },
|
||||||
|
{ "off", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "auto" },
|
||||||
|
{ "on", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "auto" },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user