You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.8 KiB
220 lines
6.8 KiB
/*****************************************************************************
|
|
* window.c : Implementation of FFT window routines
|
|
*****************************************************************************
|
|
* Copyright (C) 2014 Ronald Wright
|
|
* $Id$
|
|
*
|
|
* Author: Ronald Wright <logiconcepts819@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"
|
|
|
|
#include <assert.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 */
|
|
vlc_assert_unreachable();
|
|
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;
|
|
}
|
|
}
|
|
|