Commit 3408f466 authored by Muhammad Faiz's avatar Muhammad Faiz

avfilter/avf_showcqt: add attack option

Signed-off-by: 's avatarMuhammad Faiz <mfcc64@gmail.com>
parent 47ccefac
...@@ -17192,6 +17192,11 @@ event in time domain is represented more accurately (such as fast bass drum), ...@@ -17192,6 +17192,11 @@ event in time domain is represented more accurately (such as fast bass drum),
otherwise event in frequency domain is represented more accurately otherwise event in frequency domain is represented more accurately
(such as bass guitar). Acceptable range is @code{[0.002, 1]}. Default value is @code{0.17}. (such as bass guitar). Acceptable range is @code{[0.002, 1]}. Default value is @code{0.17}.
@item attack
Set attack time in seconds. The default is @code{0} (disabled). Otherwise, it
limits future samples by applying asymmetric windowing in time domain, useful
when low latency is required. Accepted range is @code{[0, 1]}.
@item basefreq @item basefreq
Specify the transform base frequency. Default value is @code{20.01523126408007475}, Specify the transform base frequency. Default value is @code{20.01523126408007475},
which is frequency 50 cents below E0. Acceptable range is @code{[10, 100000]}. which is frequency 50 cents below E0. Acceptable range is @code{[10, 100000]}.
......
...@@ -78,6 +78,7 @@ static const AVOption showcqt_options[] = { ...@@ -78,6 +78,7 @@ static const AVOption showcqt_options[] = {
{ "bar_t", "set bar transparency", OFFSET(bar_t), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 1.0, FLAGS }, { "bar_t", "set bar transparency", OFFSET(bar_t), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 1.0, FLAGS },
{ "timeclamp", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.002, 1.0, FLAGS }, { "timeclamp", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.002, 1.0, FLAGS },
{ "tc", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.002, 1.0, FLAGS }, { "tc", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.002, 1.0, FLAGS },
{ "attack", "set attack time", OFFSET(attack), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0.0, 1.0, FLAGS },
{ "basefreq", "set base frequency", OFFSET(basefreq), AV_OPT_TYPE_DOUBLE, { .dbl = BASEFREQ }, 10.0, 100000.0, FLAGS }, { "basefreq", "set base frequency", OFFSET(basefreq), AV_OPT_TYPE_DOUBLE, { .dbl = BASEFREQ }, 10.0, 100000.0, FLAGS },
{ "endfreq", "set end frequency", OFFSET(endfreq), AV_OPT_TYPE_DOUBLE, { .dbl = ENDFREQ }, 10.0, 100000.0, FLAGS }, { "endfreq", "set end frequency", OFFSET(endfreq), AV_OPT_TYPE_DOUBLE, { .dbl = ENDFREQ }, 10.0, 100000.0, FLAGS },
{ "coeffclamp", "set coeffclamp", OFFSET(coeffclamp), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.1, 10.0, FLAGS }, { "coeffclamp", "set coeffclamp", OFFSET(coeffclamp), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.1, 10.0, FLAGS },
...@@ -152,6 +153,7 @@ static void common_uninit(ShowCQTContext *s) ...@@ -152,6 +153,7 @@ static void common_uninit(ShowCQTContext *s)
av_freep(&s->fft_data); av_freep(&s->fft_data);
av_freep(&s->fft_result); av_freep(&s->fft_result);
av_freep(&s->cqt_result); av_freep(&s->cqt_result);
av_freep(&s->attack_data);
av_freep(&s->c_buf); av_freep(&s->c_buf);
av_freep(&s->h_buf); av_freep(&s->h_buf);
av_freep(&s->rcp_h_buf); av_freep(&s->rcp_h_buf);
...@@ -1138,6 +1140,14 @@ static int plot_cqt(AVFilterContext *ctx, AVFrame **frameout) ...@@ -1138,6 +1140,14 @@ static int plot_cqt(AVFilterContext *ctx, AVFrame **frameout)
last_time = av_gettime(); last_time = av_gettime();
memcpy(s->fft_result, s->fft_data, s->fft_len * sizeof(*s->fft_data)); memcpy(s->fft_result, s->fft_data, s->fft_len * sizeof(*s->fft_data));
if (s->attack_data) {
int k;
for (k = 0; k < s->remaining_fill_max; k++) {
s->fft_result[s->fft_len/2+k].re *= s->attack_data[k];
s->fft_result[s->fft_len/2+k].im *= s->attack_data[k];
}
}
av_fft_permute(s->fft_ctx, s->fft_result); av_fft_permute(s->fft_ctx, s->fft_result);
av_fft_calc(s->fft_ctx, s->fft_result); av_fft_calc(s->fft_ctx, s->fft_result);
s->fft_result[s->fft_len] = s->fft_result[0]; s->fft_result[s->fft_len] = s->fft_result[0];
...@@ -1377,6 +1387,21 @@ static int config_output(AVFilterLink *outlink) ...@@ -1377,6 +1387,21 @@ static int config_output(AVFilterLink *outlink)
if (!s->fft_ctx || !s->fft_data || !s->fft_result || !s->cqt_result) if (!s->fft_ctx || !s->fft_data || !s->fft_result || !s->cqt_result)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
s->remaining_fill_max = s->fft_len / 2;
if (s->attack > 0.0) {
int k;
s->remaining_fill_max = FFMIN(s->remaining_fill_max, ceil(inlink->sample_rate * s->attack));
s->attack_data = av_malloc_array(s->remaining_fill_max, sizeof(*s->attack_data));
if (!s->attack_data)
return AVERROR(ENOMEM);
for (k = 0; k < s->remaining_fill_max; k++) {
double y = M_PI * k / (inlink->sample_rate * s->attack);
s->attack_data[k] = 0.355768 + 0.487396 * cos(y) + 0.144232 * cos(2*y) + 0.012604 * cos(3*y);
}
}
s->cqt_align = 1; s->cqt_align = 1;
s->cqt_calc = cqt_calc; s->cqt_calc = cqt_calc;
s->permute_coeffs = NULL; s->permute_coeffs = NULL;
...@@ -1435,7 +1460,7 @@ static int config_output(AVFilterLink *outlink) ...@@ -1435,7 +1460,7 @@ static int config_output(AVFilterLink *outlink)
s->sono_count = 0; s->sono_count = 0;
s->next_pts = 0; s->next_pts = 0;
s->sono_idx = 0; s->sono_idx = 0;
s->remaining_fill = s->fft_len / 2; s->remaining_fill = s->remaining_fill_max;
s->remaining_frac = 0; s->remaining_frac = 0;
s->step_frac = av_div_q(av_make_q(inlink->sample_rate, s->count) , s->rate); s->step_frac = av_div_q(av_make_q(inlink->sample_rate, s->count) , s->rate);
s->step = (int)(s->step_frac.num / s->step_frac.den); s->step = (int)(s->step_frac.num / s->step_frac.den);
...@@ -1463,15 +1488,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) ...@@ -1463,15 +1488,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
AVFrame *out = NULL; AVFrame *out = NULL;
if (!insamples) { if (!insamples) {
while (s->remaining_fill < s->fft_len / 2) { while (s->remaining_fill < s->remaining_fill_max) {
memset(&s->fft_data[s->fft_len - s->remaining_fill], 0, sizeof(*s->fft_data) * s->remaining_fill); memset(&s->fft_data[s->fft_len/2 + s->remaining_fill_max - s->remaining_fill], 0, sizeof(*s->fft_data) * s->remaining_fill);
ret = plot_cqt(ctx, &out); ret = plot_cqt(ctx, &out);
if (ret < 0) if (ret < 0)
return ret; return ret;
step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den; step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den;
s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den; s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den;
for (x = 0; x < (s->fft_len-step); x++) for (x = 0; x < (s->fft_len/2 + s->remaining_fill_max - step); x++)
s->fft_data[x] = s->fft_data[x+step]; s->fft_data[x] = s->fft_data[x+step];
s->remaining_fill += step; s->remaining_fill += step;
...@@ -1486,7 +1511,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) ...@@ -1486,7 +1511,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
while (remaining) { while (remaining) {
i = insamples->nb_samples - remaining; i = insamples->nb_samples - remaining;
j = s->fft_len - s->remaining_fill; j = s->fft_len/2 + s->remaining_fill_max - s->remaining_fill;
if (remaining >= s->remaining_fill) { if (remaining >= s->remaining_fill) {
for (m = 0; m < s->remaining_fill; m++) { for (m = 0; m < s->remaining_fill; m++) {
s->fft_data[j+m].re = audio_data[2*(i+m)]; s->fft_data[j+m].re = audio_data[2*(i+m)];
...@@ -1500,7 +1525,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) ...@@ -1500,7 +1525,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
remaining -= s->remaining_fill; remaining -= s->remaining_fill;
if (out) { if (out) {
int64_t pts = av_rescale_q(insamples->pts, inlink->time_base, av_make_q(1, inlink->sample_rate)); int64_t pts = av_rescale_q(insamples->pts, inlink->time_base, av_make_q(1, inlink->sample_rate));
pts += insamples->nb_samples - remaining - s->fft_len/2; pts += insamples->nb_samples - remaining - s->remaining_fill_max;
pts = av_rescale_q(pts, av_make_q(1, inlink->sample_rate), outlink->time_base); pts = av_rescale_q(pts, av_make_q(1, inlink->sample_rate), outlink->time_base);
if (FFABS(pts - out->pts) > PTS_TOLERANCE) { if (FFABS(pts - out->pts) > PTS_TOLERANCE) {
av_log(ctx, AV_LOG_DEBUG, "changing pts from %"PRId64" (%.3f) to %"PRId64" (%.3f).\n", av_log(ctx, AV_LOG_DEBUG, "changing pts from %"PRId64" (%.3f) to %"PRId64" (%.3f).\n",
...@@ -1518,7 +1543,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) ...@@ -1518,7 +1543,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
} }
step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den; step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den;
s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den; s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den;
for (m = 0; m < s->fft_len-step; m++) for (m = 0; m < s->fft_len/2 + s->remaining_fill_max - step; m++)
s->fft_data[m] = s->fft_data[m+step]; s->fft_data[m] = s->fft_data[m+step];
s->remaining_fill = step; s->remaining_fill = step;
} else { } else {
......
...@@ -55,6 +55,7 @@ typedef struct { ...@@ -55,6 +55,7 @@ typedef struct {
AVRational step_frac; AVRational step_frac;
int remaining_frac; int remaining_frac;
int remaining_fill; int remaining_fill;
int remaining_fill_max;
int64_t next_pts; int64_t next_pts;
double *freq; double *freq;
FFTContext *fft_ctx; FFTContext *fft_ctx;
...@@ -62,6 +63,7 @@ typedef struct { ...@@ -62,6 +63,7 @@ typedef struct {
FFTComplex *fft_data; FFTComplex *fft_data;
FFTComplex *fft_result; FFTComplex *fft_result;
FFTComplex *cqt_result; FFTComplex *cqt_result;
float *attack_data;
int fft_bits; int fft_bits;
int fft_len; int fft_len;
int cqt_len; int cqt_len;
...@@ -104,6 +106,7 @@ typedef struct { ...@@ -104,6 +106,7 @@ typedef struct {
float bar_g; float bar_g;
float bar_t; float bar_t;
double timeclamp; double timeclamp;
double attack;
double basefreq; double basefreq;
double endfreq; double endfreq;
float coeffclamp; /* deprecated - ignored */ float coeffclamp; /* deprecated - ignored */
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define LIBAVFILTER_VERSION_MAJOR 6 #define LIBAVFILTER_VERSION_MAJOR 6
#define LIBAVFILTER_VERSION_MINOR 84 #define LIBAVFILTER_VERSION_MINOR 84
#define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \ LIBAVFILTER_VERSION_MINOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment