[vlc-commits] scaletempo: add pitch shifting submodule

Valentin Deniaud git at videolan.org
Tue Sep 5 14:24:36 CEST 2017


vlc | branch: master | Valentin Deniaud <valentin.deniaud at inpt.fr> | Mon Sep  4 14:56:13 2017 +0200| [d3e1f1455f85f39c383896318987c4bc9a169102] | committer: Thomas Guillem

scaletempo: add pitch shifting submodule

The idea is to load a resampler in order to change the tempo along with the
pitch, then use scaletempo to get back to the initial tempo while keeping the
adjusted pitch.

Fixes #8396

Signed-off-by: Thomas Guillem <thomas at gllm.fr>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d3e1f1455f85f39c383896318987c4bc9a169102
---

 modules/MODULES_LIST              |   2 +-
 modules/audio_filter/Makefile.am  |   1 +
 modules/audio_filter/scaletempo.c | 113 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 114 insertions(+), 2 deletions(-)

diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 698118fe5e..28dac0289f 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -339,7 +339,7 @@ $Id$
  * sapi: Windows Text to Speech Synthetizer using the SAPI 5.1 API
  * satip: SES Astra SAT>IP access module
  * scale: Images rescaler
- * scaletempo: Scale audio tempo in sync with playback rate
+ * scaletempo: Scale audio tempo in sync with playback rate, or adjust pitch without changing tempo
  * scene: scene video filter
  * schroedinger: Schroedinger video decoder
  * screen: a input module that takes screenshots of the primary monitor
diff --git a/modules/audio_filter/Makefile.am b/modules/audio_filter/Makefile.am
index 1b8a2aba38..bcff753948 100644
--- a/modules/audio_filter/Makefile.am
+++ b/modules/audio_filter/Makefile.am
@@ -16,6 +16,7 @@ libgain_plugin_la_SOURCES = audio_filter/gain.c
 libparam_eq_plugin_la_SOURCES = audio_filter/param_eq.c
 libparam_eq_plugin_la_LIBADD = $(LIBM)
 libscaletempo_plugin_la_SOURCES = audio_filter/scaletempo.c
+libscaletempo_plugin_la_LIBADD = $(LIBM)
 libstereo_widen_plugin_la_SOURCES = audio_filter/stereo_widen.c
 libspatializer_plugin_la_SOURCES = \
 	audio_filter/spatializer/allpass.cpp \
diff --git a/modules/audio_filter/scaletempo.c b/modules/audio_filter/scaletempo.c
index 39ded6fc44..2ba51b7eea 100644
--- a/modules/audio_filter/scaletempo.c
+++ b/modules/audio_filter/scaletempo.c
@@ -32,6 +32,8 @@
 #include <vlc_plugin.h>
 #include <vlc_aout.h>
 #include <vlc_filter.h>
+#include <vlc_modules.h>
+#include <vlc_atomic.h>
 
 #include <string.h> /* for memset */
 #include <limits.h> /* form INT_MIN */
@@ -40,8 +42,11 @@
  * Module descriptor
  *****************************************************************************/
 static int  Open( vlc_object_t * );
+static int  OpenPitch( vlc_object_t * );
 static void Close( vlc_object_t * );
+static void ClosePitch( vlc_object_t * );
 static block_t *DoWork( filter_t *, block_t * );
+static block_t *DoPitchWork( filter_t *, block_t * );
 
 vlc_module_begin ()
     set_description( N_("Audio tempo scaler synched with rate") )
@@ -56,8 +61,15 @@ vlc_module_begin ()
         N_("Overlap Length"), N_("Percentage of stride to overlap"), true )
     add_integer_with_range( "scaletempo-search", 14, 0, 200,
         N_("Search Length"), N_("Length in milliseconds to search for best overlap position"), true )
-
     set_callbacks( Open, Close )
+
+    add_submodule ()
+    set_shortname( N_("Pitch Shifter") )
+    set_description( N_("Audio pitch changer") )
+    set_callbacks( OpenPitch, ClosePitch )
+    add_shortcut( "pitch" )
+    add_float_with_range( "pitch-shift", 0, -12, 12,
+        N_("Pitch Shift"), N_("Pitch shift in semitones"), false )
 vlc_module_end ()
 
 /*
@@ -111,6 +123,9 @@ struct filter_sys_t
     void     *buf_pre_corr;
     void     *table_window;
     unsigned(*best_overlap_offset)( filter_t *p_filter );
+    /* pitch */
+    filter_t * resampler;
+    vlc_atomic_float rate_shift;
 };
 
 /*****************************************************************************
@@ -431,6 +446,73 @@ static int Open( vlc_object_t *p_this )
     aout_FormatPrepare(&p_filter->fmt_in.audio);
     p_filter->fmt_out.audio = p_filter->fmt_in.audio;
     p_filter->pf_audio_filter = DoWork;
+
+    return VLC_SUCCESS;
+}
+
+static inline void PitchSetRateShift( filter_sys_t *p_sys, float pitch_shift )
+{
+    vlc_atomic_store_float( &p_sys->rate_shift,
+                            p_sys->sample_rate / powf(2, pitch_shift / 12) );
+}
+
+static int PitchCallback( vlc_object_t *p_this, char const *psz_var,
+                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED( p_this );
+    VLC_UNUSED( oldval );
+    VLC_UNUSED( psz_var );
+
+    PitchSetRateShift( p_data, newval.f_float );
+
+    return VLC_SUCCESS;
+}
+
+static filter_t *ResamplerCreate(filter_t *p_filter)
+{
+    filter_t *p_resampler = vlc_object_create( p_filter, sizeof (filter_t) );
+    if( unlikely( p_resampler == NULL ) )
+        return NULL;
+
+    p_resampler->owner.sys = NULL;
+    p_resampler->p_cfg = NULL;
+    p_resampler->fmt_in = p_filter->fmt_in;
+    p_resampler->fmt_out = p_filter->fmt_in;
+    p_resampler->fmt_out.audio.i_rate =
+        vlc_atomic_load_float( &p_filter->p_sys->rate_shift );
+    aout_FormatPrepare( &p_resampler->fmt_out.audio );
+    p_resampler->p_module = module_need( p_resampler, "audio resampler", NULL,
+                                         false );
+
+    if( p_resampler->p_module == NULL )
+    {
+        msg_Err( p_filter, "Could not load resampler" );
+        vlc_object_release( p_resampler );
+        return NULL;
+    }
+    return p_resampler;
+}
+
+static int OpenPitch( vlc_object_t *p_this )
+{
+    int err = Open( p_this );
+    if( err )
+        return err;
+
+    filter_t     *p_filter = (filter_t *)p_this;
+    vlc_object_t *p_aout = p_filter->obj.parent;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    float pitch_shift  = var_CreateGetFloat( p_aout, "pitch-shift" );
+    var_AddCallback( p_aout, "pitch-shift", PitchCallback, p_sys );
+    PitchSetRateShift( p_sys, pitch_shift );
+
+    p_sys->resampler = ResamplerCreate(p_filter);
+    if( !p_sys->resampler )
+        return VLC_EGENERIC;
+
+    p_filter->pf_audio_filter = DoPitchWork;
+
     return VLC_SUCCESS;
 }
 
@@ -446,6 +528,18 @@ static void Close( vlc_object_t *p_this )
     free( p_sys );
 }
 
+static void ClosePitch( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys = p_filter->p_sys;
+    vlc_object_t *p_aout = p_filter->obj.parent;
+    var_DelCallback( p_aout, "pitch-shift", PitchCallback, p_sys );
+    var_Destroy( p_aout, "pitch-shift" );
+    module_unneed( p_sys->resampler, p_sys->resampler->p_module );
+    vlc_object_release( p_sys->resampler );
+    Close( p_this );
+}
+
 /*****************************************************************************
  * DoWork: filter wrapper for transform_buffer
  *****************************************************************************/
@@ -486,3 +580,20 @@ static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
     block_Release( p_in_buf );
     return p_out_buf;
 }
+
+static block_t *DoPitchWork( filter_t * p_filter, block_t * p_in_buf )
+{
+    filter_sys_t *p = p_filter->p_sys;
+
+    float rate_shift = vlc_atomic_load_float( &p->rate_shift );
+
+    /* Set matching rates for resampler's output and scaletempo's input */
+    p->resampler->fmt_out.audio.i_rate = rate_shift;
+    p_filter->fmt_in.audio.i_rate = rate_shift;
+
+    /* Change rate, thus changing pitch */
+    p_in_buf = p->resampler->pf_audio_filter( p->resampler, p_in_buf );
+
+    /* Change tempo while preserving shifted pitch */
+    return DoWork( p_filter, p_in_buf );
+}



More information about the vlc-commits mailing list