[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