From df1f5e2182795e2aaf904b0661c3fd7b7d3dfcda Mon Sep 17 00:00:00 2001 From: Sukrit Sangwan Date: Sat, 10 Mar 2012 17:59:12 -0800 Subject: [PATCH] stereo_widen : filter to enhance stereo Signed-off-by: Jean-Baptiste Kempf --- NEWS | 1 + modules/LIST | 1 + modules/audio_filter/Modules.am | 4 +- modules/audio_filter/stereo_widen.c | 232 ++++++++++++++++++++++++++++ 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 modules/audio_filter/stereo_widen.c diff --git a/NEWS b/NEWS index 338bf576af..0fdaef7bfa 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ Encoders: Audio Filters: * new remapping channel filter + * new filter to enhance stereo effect by mono suppression and delay effect Codecs: * Support for CDXL, Ut Video, VBLE, Dxtory codecs via libavcodec. diff --git a/modules/LIST b/modules/LIST index d6b192d588..09dbad8ad7 100644 --- a/modules/LIST +++ b/modules/LIST @@ -304,6 +304,7 @@ $Id$ * spudec: RLE DVD subtitles decoder * sqlite: manage an SQLite database * stats: Stats encoder function + * stereo_widen: Enhances stereo effect * stl: EBU STL decoder * stream_filter_dash: MPEG DASH playback * stream_filter_httplive: HTTP Live streaming for playback diff --git a/modules/audio_filter/Modules.am b/modules/audio_filter/Modules.am index d787dbb1a5..90e7661fa7 100644 --- a/modules/audio_filter/Modules.am +++ b/modules/audio_filter/Modules.am @@ -6,6 +6,7 @@ SOURCES_audiobargraph_a = audiobargraph_a.c SOURCES_param_eq = param_eq.c SOURCES_scaletempo = scaletempo.c SOURCES_chorus_flanger = chorus_flanger.c +SOURCES_stereo_widen = stereo_widen.c SOURCES_spatializer = \ spatializer/allpass.cpp spatializer/allpass.hpp \ spatializer/comb.cpp spatializer/comb.hpp \ @@ -23,7 +24,8 @@ libvlc_LTLIBRARIES += \ libnormvol_plugin.la \ libparam_eq_plugin.la \ libscaletempo_plugin.la \ - libspatializer_plugin.la + libspatializer_plugin.la \ + libstereo_widen_plugin.la # Channel mixers SOURCES_trivial_channel_mixer = channel_mixer/trivial.c diff --git a/modules/audio_filter/stereo_widen.c b/modules/audio_filter/stereo_widen.c new file mode 100644 index 0000000000..fcf93be28e --- /dev/null +++ b/modules/audio_filter/stereo_widen.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * stereo_widen.c : simple stereo widening effect + ***************************************************************************** + * Copyright (C) 2012 VLC authors and VideoLAN + * + * Author : Sukrit Sangwan < sukritsangwan at gmail dot 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 +#include +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +static block_t *Filter ( filter_t *, block_t * ); +static int paramCallback( vlc_object_t *, char const *, vlc_value_t , + vlc_value_t , void * ); + +struct filter_sys_t +{ + float *pf_begin; /* circular buffer to store samples */ + float *pf_write; /* where to write current sample */ + int i_len; /* delay in number of samples */ + float f_delay; /* delay in milliseconds */ + float f_feedback; + float f_crossfeed; + float f_dry_mix; + bool b_free_buf; /* used if callback to delay fails to * + * allocate buffer, then dont free it twice */ +}; + +#define DESCRIPTION N_("This filter enhances stereo effect by \ + suppressing mono,i.e. signal common to both channels, \ + and by delaying the signal of left into right and vice versa \ + thereby widening stereo effect") +#define DELAY_TEXT N_("Delay time") +#define DELAY_LONGTEXT N_("Time in ms of the delay of left signal into right \ + and vice versa.") +#define FEEDBACK_TEXT N_("Feedback Gain") +#define FEEDBACK_LONGTEXT N_("Amount of gain in delayed left signal into \ + right and vice versa. Gives a delay effect of left signal in \ + right output and vice versa which gives widening effect") +#define CROSSFEED_TEXT N_("Crossfeed") +#define CROSSFEED_LONGTEXT N_("Cross feed of left into right with inverted \ + phase. This helps in suppression of mono. If its value is 1 it \ + cancels all the signal common to both channels") +#define DRYMIX_TEXT N_("Dry Mix") +#define DRYMIX_LONGTEXT N_("Level of input signal of original channel") + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin () + set_shortname( N_("stereo_widen") ) + set_description( DESCRIPTION ) + set_category( CAT_AUDIO ) + set_subcategory( SUBCAT_AUDIO_AFILTER ) + set_capability( "audio filter", 0 ) + set_callbacks( Open, Close ) + + add_float( "delay", 20, DELAY_TEXT, DELAY_LONGTEXT, true ) + add_float_with_range( "feedback", 0.3, 0.0, 0.9, + FEEDBACK_TEXT, FEEDBACK_LONGTEXT, true ) + add_float_with_range( "crossfeed", 0.3, 0.0, 0.8, + CROSSFEED_TEXT, CROSSFEED_LONGTEXT, true ) + add_float_with_range( "dry-mix", 0.8, 0.0, 1.0, + DRYMIX_TEXT, DRYMIX_LONGTEXT, true ) +vlc_module_end () + +/***************************************************************************** + * Open: Allocate buffer + *****************************************************************************/ +static int Open( vlc_object_t *obj ) +{ + filter_t *p_filter = (filter_t *)obj; + filter_sys_t *p_sys; + + if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 || + !AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio) ) + return VLC_EGENERIC; + + if( p_filter->fmt_in.audio.i_channels != 2 ) + { + msg_Err ( p_filter, "stereo enhance requires stereo" ); + return VLC_EGENERIC; + } + + p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) ); + if( unlikely(!p_sys) ) + return VLC_ENOMEM; + +#define CREATE_VAR( stor, var ) \ + p_sys->stor = var_CreateGetFloat( obj, var ); \ + var_AddCallback( p_filter, var, paramCallback, p_sys ); + + CREATE_VAR( f_delay, "delay" ) + CREATE_VAR( f_feedback, "feedback" ) + CREATE_VAR( f_crossfeed, "crossfeed" ) + CREATE_VAR( f_dry_mix, "dry-mix" ) + + /* Compute buffer length and allocate space */ + p_sys->i_len = 2 * p_sys->f_delay * p_filter->fmt_in.audio.i_rate / 1000; + p_sys->pf_begin = calloc( p_sys->i_len + 2, sizeof(float) ); + if( unlikely(!p_sys->pf_begin) ) + { + free( p_sys ); + return VLC_ENOMEM; + } + p_sys->b_free_buf = true; + p_sys->pf_write = p_sys->pf_begin; + p_filter->pf_audio_filter = Filter; + return VLC_SUCCESS; +} + + +/***************************************************************************** + * Filter: process each sample + *****************************************************************************/ +static block_t *Filter( filter_t *p_filter, block_t *p_block ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + float *p_out = (float *)p_block->p_buffer; + float *pf_read; + + for (unsigned i = p_block->i_nb_samples; i > 0; i--) + { + pf_read = p_sys->pf_write + 2; + /* if at end of buffer put read ptr at begin */ + if( pf_read > p_sys->pf_begin + p_sys->i_len ) + pf_read = p_sys->pf_begin; + + float left = p_out[0]; + float right = p_out[1]; + + *(p_out++) = p_sys->f_dry_mix * left - p_sys->f_crossfeed * right + - p_sys->f_feedback * pf_read[1]; + *(p_out++) = p_sys->f_dry_mix * right - p_sys->f_crossfeed * left + - p_sys->f_feedback * pf_read[0]; + p_sys->pf_write[0] = left ; + p_sys->pf_write[1] = right; + + /* if at end of buffer place pf_write at begin */ + if( p_sys->pf_write == p_sys->pf_begin + p_sys->i_len ) + p_sys->pf_write = p_sys->pf_begin; + else + p_sys->pf_write += 2; + } + + return p_block; +} + +/***************************************************************************** + * Close: close the plugin + *****************************************************************************/ +static void Close( vlc_object_t *obj ) +{ + filter_t *p_filter = (filter_t *)obj; + filter_sys_t *p_sys = p_filter->p_sys; + +#define DEL_VAR(var) \ + var_DelCallback( p_filter, var, paramCallback, p_sys ); \ + var_Destroy( p_filter, var ); + + DEL_VAR( "feedback" ); + DEL_VAR( "crossfeed" ); + DEL_VAR( "dry-mix" ); + var_Destroy( p_filter, "delay" ); + if( p_sys->b_free_buf ) + free( p_sys->pf_begin ); + free( p_sys ); +} + + +/********************************************************************** + * Callback to update params on the fly + **********************************************************************/ +static int paramCallback( vlc_object_t *p_this, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) +{ + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys = (filter_sys_t *) p_data; + + VLC_UNUSED(oldval); + VLC_UNUSED(p_this); + + if( !strcmp( psz_var, "delay" ) ) + { + p_sys->f_delay = newval.f_float; + /* Free previous buffer and allocate new circular buffer */ + free( p_sys->pf_begin ); + p_sys->i_len = 2 * p_sys->f_delay * p_filter->fmt_in.audio.i_rate /1000; + p_sys->pf_begin = calloc( p_sys->i_len + 2, sizeof(float) ); + if( unlikely(!p_sys->pf_begin) ) + { + p_sys->b_free_buf = false; + msg_Dbg( p_filter, "Couldnt allocate buffer for delay" ); + Close( p_this ); + } + } + else if( !strcmp( psz_var, "feedback" ) ) + p_sys->f_feedback = newval.f_float; + else if( !strcmp( psz_var, "crossfeed" ) ) + p_sys->f_feedback = newval.f_float; + else if( !strcmp( psz_var, "dry-mix" ) ) + p_sys->f_dry_mix = newval.f_float; + + return VLC_SUCCESS; +} -- 2.39.2