|
|
@ -42,6 +42,7 @@ |
|
|
|
#include "window_func.h" |
|
|
|
#include "window_func.h" |
|
|
|
|
|
|
|
|
|
|
|
enum DisplayMode { COMBINED, SEPARATE, NB_MODES }; |
|
|
|
enum DisplayMode { COMBINED, SEPARATE, NB_MODES }; |
|
|
|
|
|
|
|
enum DataMode { D_MAGNITUDE, D_PHASE, NB_DMODES }; |
|
|
|
enum DisplayScale { LINEAR, SQRT, CBRT, LOG, FOURTHRT, FIFTHRT, NB_SCALES }; |
|
|
|
enum DisplayScale { LINEAR, SQRT, CBRT, LOG, FOURTHRT, FIFTHRT, NB_SCALES }; |
|
|
|
enum ColorMode { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, NB_CLMODES }; |
|
|
|
enum ColorMode { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, NB_CLMODES }; |
|
|
|
enum SlideMode { REPLACE, SCROLL, FULLFRAME, RSCROLL, NB_SLIDES }; |
|
|
|
enum SlideMode { REPLACE, SCROLL, FULLFRAME, RSCROLL, NB_SLIDES }; |
|
|
@ -60,12 +61,14 @@ typedef struct { |
|
|
|
int color_mode; ///< display color scheme
|
|
|
|
int color_mode; ///< display color scheme
|
|
|
|
int scale; |
|
|
|
int scale; |
|
|
|
float saturation; ///< color saturation multiplier
|
|
|
|
float saturation; ///< color saturation multiplier
|
|
|
|
|
|
|
|
int data; |
|
|
|
int xpos; ///< x position (current column)
|
|
|
|
int xpos; ///< x position (current column)
|
|
|
|
FFTContext *fft; ///< Fast Fourier Transform context
|
|
|
|
FFTContext *fft; ///< Fast Fourier Transform context
|
|
|
|
int fft_bits; ///< number of bits (FFT window size = 1<<fft_bits)
|
|
|
|
int fft_bits; ///< number of bits (FFT window size = 1<<fft_bits)
|
|
|
|
FFTComplex **fft_data; ///< bins holder for each (displayed) channels
|
|
|
|
FFTComplex **fft_data; ///< bins holder for each (displayed) channels
|
|
|
|
float *window_func_lut; ///< Window function LUT
|
|
|
|
float *window_func_lut; ///< Window function LUT
|
|
|
|
float **magnitudes; |
|
|
|
float **magnitudes; |
|
|
|
|
|
|
|
float **phases; |
|
|
|
int win_func; |
|
|
|
int win_func; |
|
|
|
int win_size; |
|
|
|
int win_size; |
|
|
|
double win_scale; |
|
|
|
double win_scale; |
|
|
@ -134,6 +137,9 @@ static const AVOption showspectrum_options[] = { |
|
|
|
{ "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" }, |
|
|
|
{ "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" }, |
|
|
|
{ "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS }, |
|
|
|
{ "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS }, |
|
|
|
{ "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS }, |
|
|
|
{ "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS }, |
|
|
|
|
|
|
|
{ "data", "set data mode", OFFSET(data), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_DMODES-1, FLAGS, "data" }, |
|
|
|
|
|
|
|
{ "magnitude", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_MAGNITUDE}, 0, 0, FLAGS, "data" }, |
|
|
|
|
|
|
|
{ "phase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_PHASE}, 0, 0, FLAGS, "data" }, |
|
|
|
{ NULL } |
|
|
|
{ NULL } |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -231,6 +237,11 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
av_freep(&s->magnitudes); |
|
|
|
av_freep(&s->magnitudes); |
|
|
|
av_frame_free(&s->outpicref); |
|
|
|
av_frame_free(&s->outpicref); |
|
|
|
av_audio_fifo_free(s->fifo); |
|
|
|
av_audio_fifo_free(s->fifo); |
|
|
|
|
|
|
|
if (s->phases) { |
|
|
|
|
|
|
|
for (i = 0; i < s->nb_display_channels; i++) |
|
|
|
|
|
|
|
av_freep(&s->phases[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
av_freep(&s->phases); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int query_formats(AVFilterContext *ctx) |
|
|
|
static int query_formats(AVFilterContext *ctx) |
|
|
@ -329,6 +340,15 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s->phases = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes)); |
|
|
|
|
|
|
|
if (!s->phases) |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
for (i = 0; i < s->nb_display_channels; i++) { |
|
|
|
|
|
|
|
s->phases[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->phases)); |
|
|
|
|
|
|
|
if (!s->phases[i]) |
|
|
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data)); |
|
|
|
s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data)); |
|
|
|
if (!s->fft_data) |
|
|
|
if (!s->fft_data) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
return AVERROR(ENOMEM); |
|
|
@ -427,6 +447,7 @@ static void run_fft(ShowSpectrumContext *s, AVFrame *fin) |
|
|
|
#define RE(y, ch) s->fft_data[ch][y].re |
|
|
|
#define RE(y, ch) s->fft_data[ch][y].re |
|
|
|
#define IM(y, ch) s->fft_data[ch][y].im |
|
|
|
#define IM(y, ch) s->fft_data[ch][y].im |
|
|
|
#define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch)) |
|
|
|
#define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch)) |
|
|
|
|
|
|
|
#define PHASE(y, ch) atan2(IM(y, ch), RE(y, ch)) |
|
|
|
|
|
|
|
|
|
|
|
static void calc_magnitudes(ShowSpectrumContext *s) |
|
|
|
static void calc_magnitudes(ShowSpectrumContext *s) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -440,6 +461,18 @@ static void calc_magnitudes(ShowSpectrumContext *s) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void calc_phases(ShowSpectrumContext *s) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int ch, y, h = s->orientation == VERTICAL ? s->h : s->w; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (ch = 0; ch < s->nb_display_channels; ch++) { |
|
|
|
|
|
|
|
float *phases = s->phases[ch]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (y = 0; y < h; y++) |
|
|
|
|
|
|
|
phases[y] = (PHASE(y, ch) / M_PI + 1) / 2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void acalc_magnitudes(ShowSpectrumContext *s) |
|
|
|
static void acalc_magnitudes(ShowSpectrumContext *s) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ch, y, h = s->orientation == VERTICAL ? s->h : s->w; |
|
|
|
int ch, y, h = s->orientation == VERTICAL ? s->h : s->w; |
|
|
@ -578,7 +611,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
ShowSpectrumContext *s = ctx->priv; |
|
|
|
ShowSpectrumContext *s = ctx->priv; |
|
|
|
AVFrame *outpicref = s->outpicref; |
|
|
|
AVFrame *outpicref = s->outpicref; |
|
|
|
const double w = s->win_scale; |
|
|
|
const double w = s->data == D_PHASE ? 1 : s->win_scale; |
|
|
|
const float g = s->gain; |
|
|
|
const float g = s->gain; |
|
|
|
int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; |
|
|
|
int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; |
|
|
|
|
|
|
|
|
|
|
@ -590,6 +623,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
|
|
|
|
|
|
|
for (ch = 0; ch < s->nb_display_channels; ch++) { |
|
|
|
for (ch = 0; ch < s->nb_display_channels; ch++) { |
|
|
|
float *magnitudes = s->magnitudes[ch]; |
|
|
|
float *magnitudes = s->magnitudes[ch]; |
|
|
|
|
|
|
|
float *phases = s->phases[ch]; |
|
|
|
float yf, uf, vf; |
|
|
|
float yf, uf, vf; |
|
|
|
|
|
|
|
|
|
|
|
/* decide color range */ |
|
|
|
/* decide color range */ |
|
|
@ -599,9 +633,20 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
for (y = 0; y < h; y++) { |
|
|
|
for (y = 0; y < h; y++) { |
|
|
|
int row = (s->mode == COMBINED) ? y : ch * h + y; |
|
|
|
int row = (s->mode == COMBINED) ? y : ch * h + y; |
|
|
|
float *out = &s->combine_buffer[3 * row]; |
|
|
|
float *out = &s->combine_buffer[3 * row]; |
|
|
|
|
|
|
|
float a; |
|
|
|
|
|
|
|
|
|
|
|
/* get magnitude */ |
|
|
|
switch (s->data) { |
|
|
|
float a = g * w * magnitudes[y]; |
|
|
|
case D_MAGNITUDE: |
|
|
|
|
|
|
|
/* get magnitude */ |
|
|
|
|
|
|
|
a = g * w * magnitudes[y]; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case D_PHASE: |
|
|
|
|
|
|
|
/* get phase */ |
|
|
|
|
|
|
|
a = phases[y]; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
av_assert0(0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* apply scale */ |
|
|
|
/* apply scale */ |
|
|
|
switch (s->scale) { |
|
|
|
switch (s->scale) { |
|
|
@ -766,7 +811,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
av_assert0(fin->nb_samples == s->win_size); |
|
|
|
av_assert0(fin->nb_samples == s->win_size); |
|
|
|
|
|
|
|
|
|
|
|
run_fft(s, fin); |
|
|
|
run_fft(s, fin); |
|
|
|
calc_magnitudes(s); |
|
|
|
if (s->data == D_MAGNITUDE) |
|
|
|
|
|
|
|
calc_magnitudes(s); |
|
|
|
|
|
|
|
if (s->data == D_PHASE) |
|
|
|
|
|
|
|
calc_phases(s); |
|
|
|
|
|
|
|
|
|
|
|
ret = plot_spectrum_column(inlink, fin); |
|
|
|
ret = plot_spectrum_column(inlink, fin); |
|
|
|
av_frame_free(&fin); |
|
|
|
av_frame_free(&fin); |
|
|
|