Commit d3e1f145 authored by Valentin Deniaud's avatar Valentin Deniaud Committed by 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's avatarThomas Guillem <thomas@gllm.fr>
parent fddcc100
......@@ -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
......
......@@ -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 \
......
......@@ -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 );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment