[vlc-devel] [PATCH 1/2] Introducing FFT windowing routines for spectrum-based visualizations

Ronald Wright logiconcepts819 at gmail.com
Fri Feb 7 19:12:00 CET 2014


This patch introduces FFT windowing routines to reduce spectral leakage in
spectrum-based visualizations.  It supports four types of windows that are
commonly used in spectrum analyzers (besides the pre-existing rectangular
window):  Hann, flat top, Blackman-Harris, and Kaiser.
---
 modules/visualization/visual/window.c         | 217 ++++++++++++++++++++++++++
 modules/visualization/visual/window.h         |  66 ++++++++
 modules/visualization/visual/window_presets.h |  37 +++++
 3 files changed, 320 insertions(+)
 create mode 100644 modules/visualization/visual/window.c
 create mode 100644 modules/visualization/visual/window.h
 create mode 100644 modules/visualization/visual/window_presets.h

diff --git a/modules/visualization/visual/window.c b/modules/visualization/visual/window.c
new file mode 100644
index 0000000..f30ffc8
--- /dev/null
+++ b/modules/visualization/visual/window.c
@@ -0,0 +1,217 @@
+/*****************************************************************************
+ * window.c : Implementation of FFT window routines
+ *****************************************************************************
+ * Copyright (C) 2014 Ronald Wright
+ * $Id$
+ *
+ * Author: Ronald Wright <logiconcepts819 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+#include "window.h"
+#include "window_presets.h"
+
+/* Flat top window coefficients */
+#define FT_A0 1.000f
+#define FT_A1 1.930f
+#define FT_A2 1.290f
+#define FT_A3 0.388f
+#define FT_A4 0.028f
+
+/* Blackman-Harris window coefficients */
+#define BH_A0 0.35875f
+#define BH_A1 0.48829f
+#define BH_A2 0.14128f
+#define BH_A3 0.01168f
+
+/*
+ * The modified Bessel function I0(x).  See Chapter 6 of the "Numerical Recipes
+ * in C: The Art of Scientific Computing" book at
+ * http://www.aip.de/groups/soe/local/numres/bookcpdf/c6-6.pdf
+ */
+static float bessi0( float x )
+{
+    float ax, ans;
+    double y; /* Accumulate polynomials in double precision. */
+    if( ( ax = fabsf( x ) ) < 3.75f ) /* Polynomial fit. */
+    {
+        y = x / 3.75;
+        y *= y;
+        ans = 1.0 + y * ( 3.5156229 + y * ( 3.0899424 + y * ( 1.2067492
+                  + y * ( 0.2659732 + y * ( 0.360768e-1
+                  + y * 0.45813e-2 ) ) ) ) );
+    }
+    else
+    {
+        y = 3.75 / ax;
+        ans = ( exp( ax ) / sqrt( ax ) ) * ( 0.39894228 + y * ( 0.1328592e-1
+            + y * ( 0.225319e-2 + y * ( -0.157565e-2 + y * ( 0.916281e-2
+            + y * ( -0.2057706e-1 + y * ( 0.2635537e-1 + y * ( -0.1647633e-1
+            + y * 0.392377e-2 ) ) ) ) ) ) ) );
+    }
+    return ans;
+}
+
+/*
+ * Obtain the window type from the window type variable.
+ */
+void window_get_param( vlc_object_t * p_aout, window_param * p_param )
+{
+    /* Fetch Kaiser parameter */
+    p_param->f_kaiser_alpha = var_InheritFloat( p_aout, "effect-kaiser-param" );
+
+    /* Fetch window type */
+    char * psz_preset = var_InheritString( p_aout, "effect-fft-window" );
+    if( !psz_preset )
+    {
+        goto no_preset;
+    }
+
+    for( int i = 0; i < NB_WINDOWS; i++ )
+    {
+        if( !strcasecmp( psz_preset, window_list[i] ) )
+        {
+            p_param->wind_type = i;
+            return;
+        }
+    }
+
+no_preset:
+    msg_Warn( p_aout, "No matching window preset found; using rectangular "
+                      "window (i.e. no window)" );
+    p_param->wind_type = NONE;
+}
+
+/*
+ * Initialization routine - sets up a lookup table for scaling a sample of data
+ * by window data.  If the lookup table is successfully allocated, its memory
+ * location and its specified size are stored at the specified memory location
+ * of the internal context.
+ * Returns true if initialization succeeded and returns false otherwise.
+ * The internal context should be freed when it is finished with, by
+ * window_close().
+ */
+bool window_init( int i_buffer_size, window_param * p_param,
+                  window_context * p_ctx )
+{
+    float * pf_table = NULL;
+    window_type wind_type = p_param->wind_type;
+
+    if( wind_type != HANN && wind_type != FLATTOP
+                          && wind_type != BLACKMANHARRIS
+                          && wind_type != KAISER )
+    {
+        /* Assume a rectangular window (i.e. no window) */
+        i_buffer_size = 0;
+        goto exit;
+    }
+
+    pf_table = malloc( i_buffer_size * sizeof( *pf_table ) );
+    if( !pf_table )
+    {
+        /* Memory allocation failed */
+        return false;
+    }
+
+    int i_buffer_size_minus_1 = i_buffer_size - 1;
+    switch( wind_type )
+    {
+    case HANN:
+        /* Hann window */
+        for( int i = 0; i < i_buffer_size; i++ )
+        {
+            float f_val = (float) i / (float) i_buffer_size_minus_1;
+            pf_table[i] = 0.5f - 0.5f * cosf( 2.0f * (float) M_PI * f_val );
+        }
+        break;
+    case FLATTOP:
+        /* Flat top window */
+        for( int i = 0; i < i_buffer_size; i++ )
+        {
+            float f_val = (float) i / (float) i_buffer_size_minus_1;
+            pf_table[i] = FT_A0
+                        - FT_A1 * cosf( 2.0f * (float) M_PI * f_val )
+                        + FT_A2 * cosf( 4.0f * (float) M_PI * f_val )
+                        - FT_A3 * cosf( 6.0f * (float) M_PI * f_val )
+                        + FT_A4 * cosf( 8.0f * (float) M_PI * f_val );
+        }
+        break;
+    case BLACKMANHARRIS:
+        /* Blackman-Harris window */
+        for( int i = 0; i < i_buffer_size; i++ )
+        {
+            float f_val = (float) i / (float) i_buffer_size_minus_1;
+            pf_table[i] = BH_A0
+                        - BH_A1 * cosf( 2.0f * (float) M_PI * f_val )
+                        + BH_A2 * cosf( 4.0f * (float) M_PI * f_val )
+                        - BH_A3 * cosf( 6.0f * (float) M_PI * f_val );
+        }
+        break;
+    case KAISER:
+    {
+        /* Kaiser window */
+        float f_pialph = (float) M_PI * p_param->f_kaiser_alpha;
+        float f_bessi0_pialph = bessi0( f_pialph );
+        for( int i = 0; i < i_buffer_size; i++ )
+        {
+            float f_val = (float) i / (float) i_buffer_size_minus_1;
+            float f_term_to_square = 2.0f * f_val - 1.0f;
+            float f_sqd_term = f_term_to_square * f_term_to_square;
+            float f_sqr_term = sqrtf( 1.0f - f_sqd_term );
+            pf_table[i] = bessi0( f_pialph * f_sqr_term ) / f_bessi0_pialph;
+        }
+        break;
+    }
+    default:
+        /* We should not reach here */
+        break;
+    }
+
+exit:
+    p_ctx->pf_window_table = pf_table;
+    p_ctx->i_buffer_size = i_buffer_size;
+    return true;
+}
+
+/*
+ * Perform an in-place scaling of the input buffer by the window data
+ * referenced from the specified context.
+ */
+void window_scale_in_place( int16_t * p_buffer, window_context * p_ctx )
+{
+    for( int i = 0; i < p_ctx->i_buffer_size; i++ )
+    {
+        p_buffer[i] *= p_ctx->pf_window_table[i];
+    }
+}
+
+/*
+ * Free the context.
+ */
+void window_close( window_context * p_ctx )
+{
+    if( p_ctx->pf_window_table )
+    {
+        free( p_ctx->pf_window_table );
+        p_ctx->pf_window_table = NULL;
+        p_ctx->i_buffer_size = 0;
+    }
+}
diff --git a/modules/visualization/visual/window.h b/modules/visualization/visual/window.h
new file mode 100644
index 0000000..d8403aa
--- /dev/null
+++ b/modules/visualization/visual/window.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * window.h : Header for FFT window routines
+ *****************************************************************************
+ * Copyright (C) 2014 Ronald Wright
+ * $Id$
+ *
+ * Author: Ronald Wright <logiconcepts819 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _WINDOW_H_
+#define _WINDOW_H_
+
+#include <vlc_common.h>
+
+/* Window type enum */
+enum _enum_window_type { NONE, HANN, FLATTOP, BLACKMANHARRIS, KAISER };
+
+/* Window context structure */
+struct _struct_window_context {
+
+    /* Storage for window function values */
+    float * pf_window_table;
+
+    /* Buffer size for the window */
+    int i_buffer_size;
+};
+
+typedef enum _enum_window_type window_type;
+
+/* Window parameter structure */
+struct _struct_window_param {
+
+    /* Window type */
+    window_type wind_type;
+
+    /* Kaiser window parameter */
+    float f_kaiser_alpha;
+};
+
+/* Prototypes for the window function */
+typedef struct _struct_window_context window_context;
+typedef struct _struct_window_param window_param;
+void window_get_param( vlc_object_t * p_aout, window_param * p_param );
+bool window_init( int i_buffer_size, window_param * p_param,
+                  window_context * p_ctx );
+void window_scale_in_place( int16_t * p_buffer, window_context * p_ctx );
+void window_close( window_context * p_ctx );
+
+/* Macro for defining a new window context */
+#define DEFINE_WIND_CONTEXT(name) window_context name = {NULL, 0}
+
+#endif /* _WINDOW_H_ */
diff --git a/modules/visualization/visual/window_presets.h b/modules/visualization/visual/window_presets.h
new file mode 100644
index 0000000..09e8d3a
--- /dev/null
+++ b/modules/visualization/visual/window_presets.h
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * window_presets.h : Variable names and strings of FFT window presets
+ *****************************************************************************
+ * Copyright (C) 2014 Ronald Wright
+ * $Id$
+ *
+ * Author: Ronald Wright <logiconcepts819 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _WINDOW_PRESETS_
+#define _WINDOW_PRESETS_
+
+/* Window functions supported by VLC. These are the typical window types used
+ * in spectrum analyzers. */
+#define NB_WINDOWS 5
+static const char * const window_list[NB_WINDOWS] = {
+    "none", "hann", "flattop", "blackmanharris", "kaiser",
+};
+static const char * const window_list_text[NB_WINDOWS] = {
+    N_("None"), N_("Hann"), N_("Flat Top"), N_("Blackman-Harris"), N_("Kaiser"),
+};
+
+#endif /* _WINDOW_PRESETS_ */
-- 
1.8.3.2




More information about the vlc-devel mailing list