[vlc-devel] [PATCH WIP 1/2] add pitch shift audio filter

Valentin Deniaud valentin.deniaud at inpt.fr
Fri Aug 18 17:43:56 CEST 2017


Fixes #8396
---
This is an attempt at a simple fix of an old issue, by using an external lib.
Just want to know if this will get shot down before throwing more work at it.


 modules/MODULES_LIST             |   1 +
 modules/audio_filter/Makefile.am |   5 +-
 modules/audio_filter/pitch.cpp   | 197 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 modules/audio_filter/pitch.cpp

diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 9509eba71d..e20f30d4b8 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -297,6 +297,7 @@ $Id$
  * packetizer_vc1: VC-1 video packetizer
  * panoramix: image wall panoramic video with edge blending filter
  * param_eq: parametric equalizer
+ * pitch: Adjust pitch without changing tempo
  * playlist: playlist import module
  * png: PNG images decoder
  * podcast: podcast feed parser
diff --git a/modules/audio_filter/Makefile.am b/modules/audio_filter/Makefile.am
index 1b8a2aba38..82cfa2762e 100644
--- a/modules/audio_filter/Makefile.am
+++ b/modules/audio_filter/Makefile.am
@@ -17,6 +17,8 @@ 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
+libpitch_plugin_la_SOURCES = audio_filter/pitch.cpp
+libpitch_plugin_la_LIBADD = $(SOUNDTOUCH_LIBS)
 libspatializer_plugin_la_SOURCES = \
 	audio_filter/spatializer/allpass.cpp \
 	audio_filter/spatializer/allpass.hpp \
@@ -41,7 +43,8 @@ audio_filter_LTLIBRARIES = \
 	libparam_eq_plugin.la \
 	libscaletempo_plugin.la \
 	libspatializer_plugin.la \
-	libstereo_widen_plugin.la
+	libstereo_widen_plugin.la \
+	libpitch_plugin.la
 
 # Channel mixers
 libdolby_surround_decoder_plugin_la_SOURCES = \
diff --git a/modules/audio_filter/pitch.cpp b/modules/audio_filter/pitch.cpp
new file mode 100644
index 0000000000..3812f6537a
--- /dev/null
+++ b/modules/audio_filter/pitch.cpp
@@ -0,0 +1,197 @@
+/*****************************************************************************
+ * pitch.cpp : Change pitch without changing tempo using SoundTouch
+ *****************************************************************************
+ * 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 <assert.h>
+#include <soundtouch/SoundTouch.h>
+
+#define BUFF_SIZE           6720
+
+
+/*****************************************************************************
+ * 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 * );
+
+using namespace soundtouch;
+
+struct filter_sys_t
+{
+    float f_shift; // pitch shift in semitones
+    SoundTouch * p_SoundTouch;
+};
+
+
+#define HELP_TEXT N_("Adjust pitch without changing tempo")
+#define SHIFT_TEXT N_("Shift pitch")
+#define SHIFT_LONGTEXT N_("Value is in semitones and can be "\
+        "positive or negative.")
+
+#define CONFIG_PREFIX "pitch-"
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin ()
+    set_shortname( N_("Pitch Shifter") )
+    set_description( N_("Adjust pitch without changing tempo") )
+    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 "shift", 0, -12.0, 12.0,
+        SHIFT_TEXT, SHIFT_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;
+
+    /* Allocate internal state */
+    filter_sys_t *p_sys = (filter_sys_t *) malloc(sizeof (filter_sys_t));
+    if (unlikely(p_sys == NULL))
+        return VLC_ENOMEM;
+    p_filter->p_sys = p_sys;
+
+    p_sys->f_shift = var_CreateGetFloat( p_aout, CONFIG_PREFIX "shift" );
+    var_AddCallback( p_aout, CONFIG_PREFIX "shift", paramCallback, p_sys );
+
+    SoundTouch * p_SoundTouch = new SoundTouch;
+    p_SoundTouch->setSampleRate(p_filter->fmt_in.audio.i_rate);
+    p_SoundTouch->setChannels( aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
+
+    p_SoundTouch->setTempoChange(0);
+    p_SoundTouch->setPitchSemiTones(p_sys->f_shift);
+    p_SoundTouch->setRateChange(0);
+
+    p_sys->p_SoundTouch = p_SoundTouch;
+
+    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;
+
+    if( !p_block || !p_block->i_nb_samples )
+    {
+        if( p_block )
+            block_Release( p_block );
+        return NULL;
+    }
+
+    int nSamples = p_block->i_nb_samples;
+
+    p_sys->p_SoundTouch->putSamples((const float*) p_block->p_buffer, nSamples);
+
+    int available_samples = p_sys->p_SoundTouch->numSamples();
+
+    if( !available_samples ) {
+        block_Release( p_block );
+        return NULL;
+    }
+
+    int nChannels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
+    int bufsize = available_samples * nChannels * sizeof(float);
+
+    block_t *p_out = block_Alloc( bufsize );
+    if( !p_out )
+    {
+        msg_Warn( p_filter, "can't get output buffer" );
+        block_Release( p_block );
+        return NULL;
+    }
+    memset( p_out->p_buffer, 0, bufsize );
+
+    nSamples = p_sys->p_SoundTouch->receiveSamples( (float*) p_out->p_buffer, bufsize / nChannels);
+
+    p_out->i_nb_samples = nSamples;
+    p_out->i_dts        = p_block->i_dts;
+    p_out->i_pts        = p_block->i_pts;
+    p_out->i_length     = p_block->i_length;
+    p_out->i_buffer = nSamples * nChannels;
+
+    block_Release( p_block );
+    return p_out;
+}
+
+/*****************************************************************************
+ * 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 "shift" );
+
+    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 "shift" ) ) {
+        p_sys->f_shift = newval.f_float;
+        p_sys->p_SoundTouch->setPitchSemiTones(p_sys->f_shift);
+    }
+
+    return VLC_SUCCESS;
+}
-- 
2.14.1


More information about the vlc-devel mailing list