Commit df1f5e21 authored by Sukrit Sangwan's avatar Sukrit Sangwan Committed by Jean-Baptiste Kempf

stereo_widen : filter to enhance stereo

Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 94566cad
......@@ -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.
......
......@@ -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
......
......@@ -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
......
/*****************************************************************************
* 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 <vlc_common.h>
#include <vlc_aout.h>
#include <vlc_filter.h>
#include <vlc_plugin.h>
/*****************************************************************************
* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment