[vlc-devel] [PATCH 1/2] add pitch shifting submodule

Valentin Deniaud valentin.deniaud at inpt.fr
Tue Aug 29 11:22:36 CEST 2017


Fixes #8396
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.
---
 modules/MODULES_LIST              |   2 +-
 modules/audio_filter/scaletempo.c | 109 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 9509eba71d..2526d1f220 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -333,7 +333,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/scaletempo.c b/modules/audio_filter/scaletempo.c
index 39ded6fc44..2b79006cd5 100644
--- a/modules/audio_filter/scaletempo.c
+++ b/modules/audio_filter/scaletempo.c
@@ -32,6 +32,7 @@
 #include <vlc_plugin.h>
 #include <vlc_aout.h>
 #include <vlc_filter.h>
+#include <vlc_modules.h>
 
 #include <string.h> /* for memset */
 #include <limits.h> /* form INT_MIN */
@@ -40,8 +41,13 @@
  * 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 * );
+static int PitchCallback( vlc_object_t *, char const *, vlc_value_t ,
+                            vlc_value_t , void * );
 
 vlc_module_begin ()
     set_description( N_("Audio tempo scaler synched with rate") )
@@ -56,8 +62,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("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 +124,10 @@ struct filter_sys_t
     void     *buf_pre_corr;
     void     *table_window;
     unsigned(*best_overlap_offset)( filter_t *p_filter );
+    /* pitch */
+    filter_t * resampler;
+    float semitone_shift;
+    float rate_shift;
 };
 
 /*****************************************************************************
@@ -380,6 +397,29 @@ static int reinit_buffers( filter_t *p_filter )
     return VLC_SUCCESS;
 }
 
+static filter_t *ResamplerCreate(filter_t *p_filter)
+{
+    filter_t *filter = vlc_object_create (p_filter, sizeof (filter_t));
+    if (unlikely(filter == NULL))
+        return NULL;
+
+    filter->owner.sys = NULL;
+    filter->p_cfg = NULL;
+    filter->fmt_in = p_filter->fmt_in;
+    filter->fmt_out = p_filter->fmt_in;
+    filter->fmt_out.audio.i_rate = p_filter->p_sys->rate_shift;
+    aout_FormatPrepare( &filter->fmt_out.audio );
+    filter->p_module = module_need (filter, "audio resampler", NULL, false);
+
+    if( filter->p_module == NULL ) {
+        msg_Err( p_filter, "Could not load resampler" );
+        vlc_object_release( filter );
+        return NULL;
+    }
+
+    return filter;
+}
+
 /*****************************************************************************
  * Open: initialize as "audio filter"
  *****************************************************************************/
@@ -431,6 +471,31 @@ 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 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;
+
+    p_sys->semitone_shift  = var_CreateGetFloat( p_aout, "pitch-shift" );
+    var_AddCallback( p_aout, "pitch-shift", PitchCallback, p_sys );
+
+    p_sys->resampler = ResamplerCreate(p_filter);
+    if( !p_sys->resampler )
+        return VLC_EGENERIC;
+
+    p_sys->rate_shift = p_filter->fmt_in.audio.i_rate \
+        / powf(2, p_sys->semitone_shift / 12);
+    p_filter->pf_audio_filter = DoPitchWork;
+
     return VLC_SUCCESS;
 }
 
@@ -446,6 +511,17 @@ 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" );
+    vlc_object_release( p_sys->resampler );
+    Close( p_this );
+}
+
 /*****************************************************************************
  * DoWork: filter wrapper for transform_buffer
  *****************************************************************************/
@@ -486,3 +562,34 @@ 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;
+
+    /* Set matching rates for resampler's output and scaletempo's input */
+    p->resampler->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate \
+                                         = p_filter->p_sys->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 );
+}
+
+/**********************************************************************
+ * Callback to adjust picth on the fly
+ **********************************************************************/
+static int PitchCallback( 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(p_this);
+    VLC_UNUSED(oldval);
+    VLC_UNUSED(psz_var);
+
+    p_sys->rate_shift = p_sys->sample_rate / powf(2, newval.f_float / 12);
+
+    return VLC_SUCCESS;
+}
-- 
2.14.1


More information about the vlc-devel mailing list