[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