[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