[vlc-devel] [PATCH 1/2] add stereo balance module

Valentin Deniaud valentin.deniaud at inpt.fr
Fri Aug 11 14:21:25 CEST 2017


Addresses #18546
---
 modules/MODULES_LIST             |   1 +
 modules/audio_filter/Makefile.am |   4 +-
 modules/audio_filter/balance.c   | 253 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+), 1 deletion(-)
 create mode 100644 modules/audio_filter/balance.c

diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 9509eba71d..796706fec3 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -58,6 +58,7 @@ $Id$
  * avformat: libavformat demuxer
  * avi: AVI file stream demuxer
  * avio: Access and Stream output module using libavformat network
+ * balance: Adjust volume between stereo channels
  * ball: Augmented reality ball video filter module
  * bandlimited_resampler: Bandlimited interpolation audio resampler
  * blend: a picture filter that blends two pictures
diff --git a/modules/audio_filter/Makefile.am b/modules/audio_filter/Makefile.am
index 1b8a2aba38..b71029e548 100644
--- a/modules/audio_filter/Makefile.am
+++ b/modules/audio_filter/Makefile.am
@@ -17,6 +17,7 @@ libparam_eq_plugin_la_SOURCES = audio_filter/param_eq.c
 libparam_eq_plugin_la_LIBADD = $(LIBM)
 libscaletempo_plugin_la_SOURCES = audio_filter/scaletempo.c
 libstereo_widen_plugin_la_SOURCES = audio_filter/stereo_widen.c
+libbalance_plugin_la_SOURCES = audio_filter/balance.c
 libspatializer_plugin_la_SOURCES = \
 	audio_filter/spatializer/allpass.cpp \
 	audio_filter/spatializer/allpass.hpp \
@@ -41,7 +42,8 @@ audio_filter_LTLIBRARIES = \
 	libparam_eq_plugin.la \
 	libscaletempo_plugin.la \
 	libspatializer_plugin.la \
-	libstereo_widen_plugin.la
+	libstereo_widen_plugin.la \
+	libbalance_plugin.la
 
 # Channel mixers
 libdolby_surround_decoder_plugin_la_SOURCES = \
diff --git a/modules/audio_filter/balance.c b/modules/audio_filter/balance.c
new file mode 100644
index 0000000000..0d6542f4b5
--- /dev/null
+++ b/modules/audio_filter/balance.c
@@ -0,0 +1,253 @@
+/*****************************************************************************
+ * balance.c : Adjust volume between stereo channels
+ *****************************************************************************
+ * Copyright (C) 2012 VLC authors and VideoLAN
+ *
+ * Author : Valentin Deniaud <valentin.deniaud at inpt.fr>
+ *
+ * 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>
+
+#include <math.h>
+
+#define ALGO(name) static void name( float *, float *, const float factor );
+
+/*****************************************************************************
+ * 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 * );
+
+ALGO(simple)
+ALGO(linear_panning)
+ALGO(square_panning)
+ALGO(transfer)
+
+#define NB_MODES 4
+#define DEFAULT_MODE "simple"
+const char* const valid_modes[NB_MODES] = {
+    "simple", "pan_lin", "pan_sqrt", "transfer" };
+
+struct filter_sys_t
+{
+    /* Value from the slider between 0 and 1 */
+    float factor;
+    /* Algorithm name */
+    const char *mode;
+    /* Corresponding function */
+    void (*algo) (float *, float *, const float);
+};
+
+#define HELP_TEXT N_("Adjust balance between left and right channels")
+#define FACTOR_TEXT N_("Factor for stereo balance")
+#define FACTOR_LONGTEXT N_("Can take any value between 0 and 1. 0.5 equals a "\
+        "balanced sound, while 0 and 1 respectively cut left and right "\
+        "channels. What happens in between depends on the mode setting.")
+#define MODE_TEXT N_("Algorithm used for balance")
+#define MODE_LONGTEXT N_("There are several available algorithms. First, "\
+        "'simple' progressively cuts the opposite channel without altering "\
+        "the volume of the other. Conversely, to avoid saturation, activating"\
+        " one of the following mode will decrease the volume upon activation."\
+        "'pan_lin' and 'pan_sqrt' respectively use linear and square root "\
+        "panning in order to move the sound from one side to another at a "\
+        "constant percieved volume. Finally 'transfer' will progressively "\
+        "merge one channel into the other (instead of dropping it).")
+
+#define CONFIG_PREFIX "balance-"
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin ()
+    set_shortname( N_("Balance") )
+    set_description( N_("Left/right balance") )
+    set_help( HELP_TEXT )
+    set_category( CAT_AUDIO )
+    set_subcategory( SUBCAT_AUDIO_AFILTER )
+    set_capability( "audio filter", 0 )
+    set_callbacks( Open, Close )
+
+    add_float_with_range( CONFIG_PREFIX "factor", 0.5, 0.0, 1.0,
+        FACTOR_TEXT, FACTOR_LONGTEXT, true )
+    add_string( CONFIG_PREFIX "mode", DEFAULT_MODE,
+        MODE_TEXT, MODE_LONGTEXT, true )
+vlc_module_end ()
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+
+static int Open( vlc_object_t *obj )
+{
+    filter_t *p_filter  = (filter_t *)obj;
+    vlc_object_t *p_aout = p_filter->obj.parent;
+
+    if (p_filter->fmt_in.audio.i_channels == 1)
+    {
+        msg_Err (p_filter, "balance has no effect on mono");
+        return VLC_EGENERIC;
+    }
+
+    /* Force stereo downmixing so that a channel can really be muted */
+    p_filter->fmt_in.audio.i_physical_channels = AOUT_CHANS_STEREO;
+    p_filter->fmt_out.audio.i_physical_channels = AOUT_CHANS_STEREO;
+    aout_FormatPrepare(&p_filter->fmt_in.audio);
+    aout_FormatPrepare(&p_filter->fmt_out.audio);
+
+    /* Allocate internal state */
+    filter_sys_t *p_sys = malloc(sizeof (filter_sys_t));
+    if (unlikely(p_sys == NULL))
+        return VLC_ENOMEM;
+    p_filter->p_sys = p_sys;
+
+    p_sys->factor = var_CreateGetFloat( p_aout, CONFIG_PREFIX "factor" );
+    var_AddCallback( p_aout, CONFIG_PREFIX "factor", paramCallback, p_sys );
+
+    p_sys->mode = var_CreateGetString( p_aout, CONFIG_PREFIX "mode" );
+    var_AddCallback( p_aout, CONFIG_PREFIX "mode", paramCallback, p_sys );
+
+    /* Check for invalid mode */
+    int i = 0;
+    while( strcmp( valid_modes[i], p_sys->mode ) && ++i < NB_MODES );
+    if( i == NB_MODES ) {
+        msg_Warn(obj, "invalid balance mode \"%s\", falling back to default",
+                p_sys->mode);
+        var_SetString( p_aout, CONFIG_PREFIX "mode", DEFAULT_MODE );
+        p_sys->mode = DEFAULT_MODE;
+    }
+
+    /* Set algorithm */
+    vlc_value_t val;
+    val.psz_string = strdup( p_sys->mode );
+    paramCallback( NULL, CONFIG_PREFIX "mode", val, val, p_sys );
+    free( val.psz_string );
+
+    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;
+
+    for (unsigned i = 0; i < p_block->i_nb_samples; i++) {
+        p_sys->algo( &p_out[0], &p_out[1], p_sys->factor );
+        p_out += 2;
+    }
+
+    return p_block;
+}
+
+/*****************************************************************************
+ * Various algorithms
+ *****************************************************************************/
+static void simple( float *left, float *right, const float factor )
+{
+    if(factor > 0.5)
+        *left *= 2 * (1 - factor);
+    else if(factor < 0.5)
+        *right *= 2 * factor;
+}
+
+
+static void linear_panning( float *left, float *right, const float pan )
+{
+    *left *= 1 - pan;
+    *right *= pan;
+}
+
+static void square_panning( float *left, float *right, const float pan )
+{
+    *left *= sqrt(1 - pan);
+    *right *= sqrt(pan);
+}
+
+static void transfer( float *left, float *right, const float factor )
+{
+    float l = *left, r = *right;
+    float doublef = factor * 2;
+    if(factor > 0.5) {
+        *right = r * (doublef - 1) + l * (doublef - 1);
+        *left *= 2 - doublef;
+    } else if(factor < 0.5) {
+        *left = l * (1 - doublef) + r * (1 - doublef);
+        *right *= doublef;
+    }
+}
+
+/*****************************************************************************
+ * Close: close the plugin
+ *****************************************************************************/
+static void Close( vlc_object_t *obj )
+{
+    filter_t *p_filter  = (filter_t *)obj;
+    vlc_object_t *p_aout = p_filter->obj.parent;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+#define DEL_VAR(var) \
+    var_DelCallback( p_aout, var, paramCallback, p_sys ); \
+    var_Destroy( p_aout, var );
+
+    DEL_VAR( CONFIG_PREFIX "factor" );
+    DEL_VAR( CONFIG_PREFIX "mode" )
+
+    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_sys_t *p_sys = (filter_sys_t *) p_data;
+
+    VLC_UNUSED(oldval);
+    VLC_UNUSED(p_this);
+
+    if( !strcmp( psz_var, CONFIG_PREFIX "factor" ) )
+        p_sys->factor = newval.f_float;
+    else if( !strcmp( psz_var, CONFIG_PREFIX "mode" ) ) {
+        p_sys->mode = newval.psz_string;
+        if( !strcmp( newval.psz_string, "simple" ) )
+            p_sys->algo = simple;
+        else if( !strcmp( newval.psz_string, "pan_lin" ) )
+            p_sys->algo = linear_panning;
+        else if( !strcmp( newval.psz_string, "pan_sqrt" ) )
+            p_sys->algo = square_panning;
+        else if( !strcmp( newval.psz_string, "transfer" ) )
+            p_sys->algo = transfer;
+    }
+
+    return VLC_SUCCESS;
+}
-- 
2.14.0


More information about the vlc-devel mailing list