[vlc-devel] [PATCH] Add Scaletempo audio filter
Rov Juvano
rovjuvano at users.sourceforge.net
Thu Jun 19 14:09:19 CEST 2008
On Wed, Jun 18, 2008 at 11:26:54PM +0200, Laurent Aimar wrote:
> As asked by Remi, are you the only author of all the code of scaletempo.c ? (as
> you have said it is "Ported from GStreamer"). If not you should add back the original
> authors.
Sole author. As well as for the MPlayer version under a
different name, which is stuck in svn due to a code freeze
just before submitting the patch. Darn my timing.
>
> > +static int StrideCallback( vlc_object_t *p_this, char const *psz_cmd,
> > +static int OverlapCallback( vlc_object_t *p_this, char const *psz_cmd,
> > +static int SearchCallback( vlc_object_t *p_this, char const *psz_cmd,
> > + vlc_value_t oldval, vlc_value_t newval, void *p_data )
> > +{
> > + VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
> > + aout_filter_sys_t *p = (aout_filter_sys_t *)p_data;
> > + uint new_value = newval.i_int;
> > + if( p->ms_search != new_value ) {
> > + p->ms_search = new_value;
> > + p->reinit_buffers = true;
> > + }
> > + return VLC_SUCCESS;
> > +}
> Those callbacks are not thread safe. They can be called while you are in
> DoWork(). You need to add a proper locking scheme. Reading your code, it
> seems you just need to lock inside these callbacks and around
> if( p->reinit_buffers ) { reinit_buffers() }
> in DoWork.
Because these values are independent of each other, are used
only within reinit_buffers, and then used only once, the worse
case scenario would be a delay for them taking effect, right?
>
> You probably want to check thoses value against sane bounds (here or in
> reinit_buffers). What happens if ms_stride is 0 for example ?
I thought they wouldn't be called if the values were out
bounds. Are the min/max of add_*_with_range just informative?
>
> > + if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2') )
> > + {
> > + b_fit = false;
> > + p_filter->input.i_format = p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
> > + msg_Warn( p_filter, "bad input or output format" );
> > + }
> > + if( ! AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
> > + {
> > + b_fit = false;
> > + memcpy( &p_filter->output, &p_filter->input, sizeof(audio_sample_format_t) );
> > + msg_Warn( p_filter, "input and output formats are not similar" );
> > + }
> > +
> > + if( ! b_fit )
> > + {
> > + return VLC_EGENERIC;
> > + }
> I am not sure you can change p_filter->input/p_filter->output if you
> return VLC_EGENERIC.
The input and output formats should be the same. Did I do
something to change them?
>
> > + p_sys = p_filter->p_sys = malloc( sizeof(aout_filter_sys_t) );
> > + if( !p_sys )
> > + {
> > + msg_Err( p_this, "Out of memory" );
> > + return VLC_ENOMEM;
> > + }
> No need to print a message when out of memory. (msg_Err needs memory too ;)
Duh. I saw this other places but should have known better.
>
> > + aout_instance_t *p_aout = (aout_instance_t *)p_filter->p_parent;
> > + p_sys->ms_stride = var_CreateGetInteger( p_aout, "scaletempo-stride" );
> > + p_sys->percent_overlap = var_CreateGetFloat( p_aout, "scaletempo-overlap" );
> > + p_sys->ms_search = var_CreateGetInteger( p_aout, "scaletempo-search" );
> I find it weird to create those variables in aout but I don't know if it is
> the current policy.
I saw other filters do it. This allows dynamically changing
the parameters. It's unnecessary, so I can change them to
config_Get...
>
> > + p->p_buffers[ p->i_buf ] = realloc( p->p_buffers[ p->i_buf ], i_outsize );
> You also have a memory leak when realloc fails (the old buffer is not
> released).
Good catch. I did this a number of times.
>
> > diff --git a/src/audio_output/input.c b/src/audio_output/input.c
> > index 184e8f7..fa62463 100644
> > --- a/src/audio_output/input.c
> > +++ b/src/audio_output/input.c
> > @@ -401,6 +401,18 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
> > }
> > p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
> >
> > + p_input->p_playback_rate_filter = NULL;
> > + for (int i=0; i < p_input->i_nb_filters; i++) {
> > + aout_filter_t * p_filter = p_input->pp_filters[i];
> > + if (strcmp ("scaletempo", p_filter->psz_object_name) == 0) {
> > + p_input->p_playback_rate_filter = p_filter;
> > + break;
> > + }
> > + }
> > + if (!p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0) {
> > + p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
> > + }
> Inside src/audio_output I would prefer you to keep current VLC code format
> style.
I meant to do that.
> I think it would be more userfriendly if scaletempo was selected by
> default (instead of specifying by audio-filter). The code loading filters
> (audio-filter) could be made a function and then reused. Of course, an option
> should be added to disable this behavior.
If there's consensus then, yeah. I don't know how to make
it the default.
>
> > - if( p_input->pp_resamplers[0]->input.i_rate == 1000 * p_input->input.i_rate / i_input_rate )
> > + uint i_nominal_rate =
> Use unsigned int instead.
Instead of what? Isn't it an unsigned int?
>
> > +/*
> > + * Scaletempo works by producing audio in constant sized chunks (a "stride") but
> > + * consuming chunks proportional to the playback rate.
> > + *
> > + * Scaletempo then smooths the output by blending the end of one stride with
> > + * the next ("overlap").
> > + *
> > + * Scaletempo smooths the overlap further by searching within the input buffer
> > + * for the best overlap position. Scaletempo uses a statistical cross correlation
> > + * (roughly a dot-product). Scaletempo consumes most of its CPU cycles here.
> > + *
> > + * NOTE:
> > + * sample: a single audio sample for one channel
> > + * frame: a single set of samples, one for each channel
> > + * VLC uses these terms differently
> > + */
> About the algo, I did find the quality a bit low (especially at high speed).
I don't doubt that, if you have good ears.
I find the VLC version produces the worse sound because
aout_InputPlay doesn't seem to like filters buffering/skipping,
which can get relatively large at high speeds. msg_Dbg
reports a lot of dropped buffers and drift correction. That's
not something I can fix. Maybe there is some way to let
aout_InputPlay know about the buffering, but I didn't figure
it out.
You can see if it sounds better with one of the versions at
http://scaletempo.sourceforge.net/
> I have played with audio time-stretching before and I had a better quality if
> I did not use "constant sized chunks".
> For that I estimate the period using autocorellation and then I duplicated or
> overlapped the audio by chunk equal to the local period. The duplication or
> overlapping amount was controled by the scale factor I wanted. It is a bit
> more complicated though.
I'd like to see more, code would be nice.
>
> Anyway the quality should not stop the integration of scaletempo, it is a
> nice feature :)
Scratching an itch.
>
> Thank you for your work.
Right back at you. You laid the groundwork.
--
rovjuvano
More information about the vlc-devel
mailing list