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

Thomas Guillem thomas at gllm.fr
Thu Aug 31 13:17:33 CEST 2017



On Tue, Aug 29, 2017, at 11:22, Valentin Deniaud wrote:
> 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;

This variable is only used locally

> +    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" );
you miss a module_unneed()
> +    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);

p_sys->rate_shift is written from any threads but read from the audio
filter thread in DoPitchWork, you need you protect it with an atomic 

> +
> +    return VLC_SUCCESS;
> +}
> -- 
> 2.14.1
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list