36 #if CONFIG_LIBFREETYPE
38 #include FT_FREETYPE_H
46 #define VIDEO_WIDTH 1920
47 #define VIDEO_HEIGHT 1080
48 #define FONT_HEIGHT 32
49 #define SPECTOGRAM_HEIGHT ((VIDEO_HEIGHT-FONT_HEIGHT)/2)
50 #define SPECTOGRAM_START (VIDEO_HEIGHT-SPECTOGRAM_HEIGHT)
51 #define BASE_FREQ 20.051392800492
52 #define COEFF_CLAMP 1.0e-4
53 #define TLENGTH_MIN 0.001
54 #define TLENGTH_DEFAULT "384/f*tc/(384/f+tc)"
55 #define VOLUME_MIN 1e-10
56 #define VOLUME_MAX 100.0
57 #define FONTCOLOR_DEFAULT "st(0, (midi(f)-59.5)/12);" \
58 "st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));" \
59 "r(1-ld(1)) + b(ld(1))"
97 #define OFFSET(x) offsetof(ShowCQTContext, x)
98 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
143 static const int samplerates[] = { 44100, 48000, -1 };
170 #if CONFIG_LIBFREETYPE
173 static const char str[] =
"EF G A BC D ";
175 FT_Library lib = NULL;
177 int video_scale = s->
fullhd ? 2 : 1;
180 int font_width = 8 * video_scale;
181 int font_repeat = font_width * 12;
182 int linear_hori_advance = font_width * 65536;
183 int non_monospace_warning = 0;
191 if (FT_Init_FreeType(&lib))
194 if (FT_New_Face(lib, s->
fontfile, 0, &face))
197 if (FT_Set_Char_Size(face, 16*64, 0, 0, 0))
200 if (FT_Load_Char(face,
'A', FT_LOAD_RENDER))
203 if (FT_Set_Char_Size(face, 16*64 * linear_hori_advance / face->glyph->linearHoriAdvance, 0, 0, 0))
210 memset(s->
font_alpha, 0, font_height * video_width);
212 for (x = 0; x < 12; x++) {
213 int sx, sy, rx, bx, by, dx, dy;
218 if (FT_Load_Char(face, str[x], FT_LOAD_RENDER))
221 if (face->glyph->advance.x != font_width*64 && !non_monospace_warning) {
223 non_monospace_warning = 1;
226 sy = font_height - 4*video_scale - face->glyph->bitmap_top;
227 for (rx = 0; rx < 10; rx++) {
228 sx = rx * font_repeat + x * font_width + face->glyph->bitmap_left;
229 for (by = 0; by < face->glyph->bitmap.rows; by++) {
233 if (dy >= font_height)
236 for (bx = 0; bx < face->glyph->bitmap.width; bx++) {
240 if (dx >= video_width)
242 s->
font_alpha[dy*video_width+dx] = face->glyph->bitmap.buffer[by*face->glyph->bitmap.width+bx];
249 FT_Done_FreeType(lib);
255 FT_Done_FreeType(lib);
263 double ret = 12200.0*12200.0 * (f*f*f*f);
264 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) *
265 sqrt((f*f + 107.7*107.7) * (f*f + 737.9*737.9));
271 double ret = 12200.0*12200.0 * (f*f*f);
272 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) * sqrt(f*f + 158.5*158.5);
278 double ret = 12200.0*12200.0 * (f*f);
279 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0);
283 static double midi(
void *p,
double f)
285 return log2(f/440.0) * 12.0 + 69.0;
290 x = av_clipd(x, 0.0, 1.0);
291 return (
int)(x*255.0+0.5) << 16;
296 x = av_clipd(x, 0.0, 1.0);
297 return (
int)(x*255.0+0.5) << 8;
302 x = av_clipd(x, 0.0, 1.0);
303 return (
int)(x*255.0+0.5);
319 AVExpr *tlength_expr = NULL, *volume_expr = NULL, *fontcolor_expr = NULL;
321 static const char *
const expr_vars[] = {
"timeclamp",
"tc",
"frequency",
"freq",
"f", NULL };
322 static const char *
const expr_func_names[] = {
"a_weighting",
"b_weighting",
"c_weighting", NULL };
323 static const char *
const expr_fontcolor_func_names[] = {
"midi",
"r",
"g",
"b", NULL };
326 int fft_len, k, x,
y,
ret;
329 double max_len = rate * (double) s->
timeclamp;
331 int video_scale = s->
fullhd ? 2 : 1;
353 #if CONFIG_LIBFREETYPE
354 load_freetype_font(ctx);
368 expr_funcs, NULL, NULL, 0, ctx);
373 expr_fontcolor_funcs, NULL, NULL, 0, ctx);
378 int hlen = fft_len >> 1;
382 double tlen, tlength, volume;
388 double a0 = 0.355768;
389 double a1 = 0.487396/
a0;
390 double a2 = 0.144232/
a0;
391 double a3 = 0.012604/
a0;
392 double sv_step, cv_step, sv, cv;
393 double sw_step, cw_step, sw, cw, w;
395 tlength =
av_expr_eval(tlength_expr, expr_vars_val, NULL);
396 if (
isnan(tlength)) {
418 if (s->
fullhd || !(k & 1)) {
419 int fontcolor =
av_expr_eval(fontcolor_expr, expr_vars_val, NULL);
420 fontcolor_value[0] = (fontcolor >> 16) & 0xFF;
421 fontcolor_value[1] = (fontcolor >> 8) & 0xFF;
422 fontcolor_value[2] = fontcolor & 0xFF;
423 fontcolor_value += 3;
426 tlen = tlength * rate;
429 s->
fft_data[hlen].
re = (1.0 + a1 + a2 +
a3) * (1.0/tlen) * volume * (1.0/fft_len);
431 sv_step = sv = sin(2.0*
M_PI*freq*(1.0/rate));
432 cv_step = cv = cos(2.0*
M_PI*freq*(1.0/rate));
434 sw_step = sw = sin(2.0*
M_PI*(1.0/tlen));
435 cw_step = cw = cos(2.0*
M_PI*(1.0/tlen));
436 for (x = 1; x < 0.5 * tlen; x++) {
437 double cv_tmp, cw_tmp;
438 double cw2, cw3, sw2;
440 cw2 = cw * cw - sw * sw;
441 sw2 = cw * sw + sw * cw;
442 cw3 = cw * cw2 - sw * sw2;
443 w = (1.0 + a1 * cw + a2 * cw2 + a3 * cw3) * (1.0/tlen) * volume * (1.0/fft_len);
449 cv_tmp = cv * cv_step - sv * sv_step;
450 sv = sv * cv_step + cv * sv_step;
452 cw_tmp = cw * cw_step - sw * sw_step;
453 sw = sw * cw_step + cw * sw_step;
456 for (; x < hlen; x++) {
465 for (x = 0; x < fft_len; x++) {
471 for (x = 0; x < fft_len; x++)
474 for (x = 0; x < fft_len; x++) {
494 av_log(ctx,
AV_LOG_INFO,
"Elapsed time %.6f s (fft_len=%u, num_coeffs=%u)\n", 1e-6 * (end_time-start_time), fft_len, num_coeffs);
496 outlink->
w = video_width;
497 outlink->
h = video_height;
535 int video_scale = s->
fullhd ? 2 : 1;
551 for (x = 1; x <= fft_len >> 1; x++) {
568 float g = 1.0f / s->
gamma;
581 result[x][0] = l.
re * l.
re + l.
im * l.
im;
582 result[x][2] = r.
re * r.
re + r.
im * r.
im;
583 result[x][1] = 0.5f * (result[x][0] + result[x][2]);
584 result[x][3] = result[x][1];
585 result[x][0] = 255.0f *
powf(
FFMIN(1.0f,result[x][0]), g);
586 result[x][1] = 255.0f *
powf(
FFMIN(1.0f,result[x][1]), g);
587 result[x][2] = 255.0f *
powf(
FFMIN(1.0f,result[x][2]), g);
591 for (x = 0; x < video_width; x++) {
592 result[x][0] = 0.5f * (result[2*x][0] + result[2*x+1][0]);
593 result[x][1] = 0.5f * (result[2*x][1] + result[2*x+1][1]);
594 result[x][2] = 0.5f * (result[2*x][2] + result[2*x+1][2]);
595 result[x][3] = 0.5f * (result[2*x][3] + result[2*x+1][3]);
599 for (x = 0; x < video_width; x++) {
608 float rcp_result[VIDEO_WIDTH];
609 int total_length = linesize * spectogram_height;
612 for (x = 0; x < video_width; x++)
613 rcp_result[x] = 1.0f / (result[x][3]+0.0001f);
616 for (y = 0; y < spectogram_height; y++) {
617 float height = (spectogram_height -
y) * (1.0f/spectogram_height);
618 uint8_t *lineptr = data + y * linesize;
619 for (x = 0; x < video_width; x++) {
621 if (result[x][3] <= height) {
626 mul = (result[x][3] -
height) * rcp_result[x];
627 *lineptr++ = mul * result[x][0] + 0.5f;
628 *lineptr++ = mul * result[x][1] + 0.5f;
629 *lineptr++ = mul * result[x][2] + 0.5f;
636 for (y = 0; y < font_height; y++) {
637 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
640 for (x = 0; x < video_width; x++) {
642 lineptr[3*x] = (spectogram_src[3*x] * (255-
alpha) + fontcolor_value[0] * alpha + 255) >> 8;
643 lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-
alpha) + fontcolor_value[1] * alpha + 255) >> 8;
644 lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-
alpha) + fontcolor_value[2] * alpha + 255) >> 8;
645 fontcolor_value += 3;
649 for (y = 0; y < font_height; y++) {
650 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
653 for (x = 0; x < video_width; x += video_width/10) {
655 static const char str[] =
"EF G A BC D ";
656 uint8_t *startptr = data + spectogram_height * linesize + x * 3;
657 for (u = 0; str[
u]; u++) {
659 for (v = 0; v < 16; v++) {
660 uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
661 int ux = x + 8 * u * video_scale;
663 for (mask = 0x80;
mask; mask >>= 1) {
668 if (video_scale == 2) {
670 p[linesize+1] = p[1];
671 p[linesize+2] = p[2];
677 p += 3 * video_scale;
686 data += spectogram_start * linesize;
689 data += total_length - back_length;
719 for (x = 0; x < (fft_len-step); x++)
727 audio_data = (
float*) insamples->
data[0];
744 for (m = 0; m < fft_len-step; m++)
751 for (m = 0; m < remaining; m++) {
800 .description =
NULL_IF_CONFIG_SMALL(
"Convert input audio to a CQT (Constant Q Transform) spectrum video output."),
806 .priv_class = &showcqt_class,