1 /*****************************************************************************
2  * scaletempo.c: Scale audio tempo while maintaining pitch
3  *****************************************************************************
4  * Copyright © 2008 VLC authors and VideoLAN
5  * $Id: d881b2e5ad7637d5dff6ddbd391ab0195d9a0874 $
6  *
7  * Authors: Rov Juvano <rovjuvano@users.sourceforge.net>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_aout.h>
34 #include <vlc_filter.h>
35 #include <vlc_modules.h>
36 #include <vlc_atomic.h>
37 
38 #include <string.h> /* for memset */
39 #include <limits.h> /* form INT_MIN */
40 
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 static int  Open( vlc_object_t * );
45 static void Close( vlc_object_t * );
46 static block_t *DoWork( filter_t *, block_t * );
47 
48 #ifdef PITCH_SHIFTER
49 static int  OpenPitch( vlc_object_t * );
50 static void ClosePitch( vlc_object_t * );
51 static block_t *DoPitchWork( filter_t *, block_t * );
52 # define MODULE_DESC N_("Pitch Shifter")
53 # define MODULES_SHORTNAME N_("Audio pitch changer")
54 #else
55 # define MODULE_DESC N_("Audio tempo scaler synched with rate")
56 # define MODULES_SHORTNAME N_("Scaletempo")
57 #endif
58 
59 vlc_module_begin ()
60     set_description( MODULE_DESC )
61     set_shortname( MODULES_SHORTNAME )
62     set_capability( "audio filter", 0 )
63     set_category( CAT_AUDIO )
64     set_subcategory( SUBCAT_AUDIO_AFILTER )
65 
66     add_integer_with_range( "scaletempo-stride", 30, 1, 2000,
67         N_("Stride Length"), N_("Length in milliseconds to output each stride"), true )
68     add_float_with_range( "scaletempo-overlap", .20, 0.0, 1.0,
69         N_("Overlap Length"), N_("Percentage of stride to overlap"), true )
70     add_integer_with_range( "scaletempo-search", 14, 0, 200,
71         N_("Search Length"), N_("Length in milliseconds to search for best overlap position"), true )
72 #ifdef PITCH_SHIFTER
73     add_float_with_range( "pitch-shift", 0, -12, 12,
74         N_("Pitch Shift"), N_("Pitch shift in semitones."), false )
75     set_callbacks( OpenPitch, ClosePitch )
76 #else
77     set_callbacks( Open, Close )
78 #endif
79 
80 vlc_module_end ()
81 
82 /*
83  * Scaletempo works by producing audio in constant sized chunks (a "stride") but
84  * consuming chunks proportional to the playback rate.
85  *
86  * Scaletempo then smooths the output by blending the end of one stride with
87  * the next ("overlap").
88  *
89  * Scaletempo smooths the overlap further by searching within the input buffer
90  * for the best overlap position.  Scaletempo uses a statistical cross correlation
91  * (roughly a dot-product).  Scaletempo consumes most of its CPU cycles here.
92  *
93  * NOTE:
94  * sample: a single audio sample for one channel
95  * frame: a single set of samples, one for each channel
96  * VLC uses these terms differently
97  */
98 struct filter_sys_t
99 {
100     /* Filter static config */
101     double    scale;
102     /* parameters */
103     unsigned  ms_stride;
104     double    percent_overlap;
105     unsigned  ms_search;
106     /* audio format */
107     unsigned  samples_per_frame;  /* AKA number of channels */
108     unsigned  bytes_per_sample;
109     unsigned  bytes_per_frame;
110     unsigned  sample_rate;
111     /* stride */
112     double    frames_stride_scaled;
113     double    frames_stride_error;
114     unsigned  bytes_stride;
115     double    bytes_stride_scaled;
116     unsigned  bytes_queue_max;
117     unsigned  bytes_queued;
118     unsigned  bytes_to_slide;
119     uint8_t  *buf_queue;
120     /* overlap */
121     unsigned  samples_overlap;
122     unsigned  samples_standing;
123     unsigned  bytes_overlap;
124     unsigned  bytes_standing;
125     void     *buf_overlap;
126     void     *table_blend;
127     void    (*output_overlap)( filter_t *p_filter, void *p_out_buf, unsigned bytes_off );
128     /* best overlap */
129     unsigned  frames_search;
130     void     *buf_pre_corr;
131     void     *table_window;
132     unsigned(*best_overlap_offset)( filter_t *p_filter );
133 #ifdef PITCH_SHIFTER
134     /* pitch */
135     filter_t * resampler;
136     vlc_atomic_float rate_shift;
137 #endif
138 };
139 
140 /*****************************************************************************
141  * best_overlap_offset: calculate best offset for overlap
142  *****************************************************************************/
best_overlap_offset_float(filter_t * p_filter)143 static unsigned best_overlap_offset_float( filter_t *p_filter )
144 {
145     filter_sys_t *p = p_filter->p_sys;
146     float *pw, *po, *ppc, *search_start;
147     float best_corr = INT_MIN;
148     unsigned best_off = 0;
149     unsigned i, off;
150 
151     pw  = p->table_window;
152     po  = p->buf_overlap;
153     po += p->samples_per_frame;
154     ppc = p->buf_pre_corr;
155     for( i = p->samples_per_frame; i < p->samples_overlap; i++ ) {
156       *ppc++ = *pw++ * *po++;
157     }
158 
159     search_start = (float *)p->buf_queue + p->samples_per_frame;
160     for( off = 0; off < p->frames_search; off++ ) {
161       float corr = 0;
162       float *ps = search_start;
163       ppc = p->buf_pre_corr;
164       for( i = p->samples_per_frame; i < p->samples_overlap; i++ ) {
165         corr += *ppc++ * *ps++;
166       }
167       if( corr > best_corr ) {
168         best_corr = corr;
169         best_off  = off;
170       }
171       search_start += p->samples_per_frame;
172     }
173 
174     return best_off * p->bytes_per_frame;
175 }
176 
177 /*****************************************************************************
178  * output_overlap: blend end of previous stride with beginning of current stride
179  *****************************************************************************/
output_overlap_float(filter_t * p_filter,void * buf_out,unsigned bytes_off)180 static void output_overlap_float( filter_t        *p_filter,
181                                   void            *buf_out,
182                                   unsigned         bytes_off )
183 {
184     filter_sys_t *p = p_filter->p_sys;
185     float *pout = buf_out;
186     float *pb   = p->table_blend;
187     float *po   = p->buf_overlap;
188     float *pin  = (float *)( p->buf_queue + bytes_off );
189     unsigned i;
190     for( i = 0; i < p->samples_overlap; i++ ) {
191         *pout++ = *po - *pb++ * ( *po - *pin++ ); po++;
192     }
193 }
194 
195 /*****************************************************************************
196  * fill_queue: fill p_sys->buf_queue as much possible, skipping samples as needed
197  *****************************************************************************/
fill_queue(filter_t * p_filter,uint8_t * p_buffer,size_t i_buffer,size_t offset)198 static size_t fill_queue( filter_t      *p_filter,
199                           uint8_t       *p_buffer,
200                           size_t         i_buffer,
201                           size_t         offset )
202 {
203     filter_sys_t *p = p_filter->p_sys;
204     unsigned bytes_in = i_buffer - offset;
205     size_t offset_unchanged = offset;
206 
207     if( p->bytes_to_slide > 0 ) {
208         if( p->bytes_to_slide < p->bytes_queued ) {
209             unsigned bytes_in_move = p->bytes_queued - p->bytes_to_slide;
210             memmove( p->buf_queue,
211                      p->buf_queue + p->bytes_to_slide,
212                      bytes_in_move );
213             p->bytes_to_slide = 0;
214             p->bytes_queued   = bytes_in_move;
215         } else {
216             unsigned bytes_in_skip;
217             p->bytes_to_slide -= p->bytes_queued;
218             bytes_in_skip      = __MIN( p->bytes_to_slide, bytes_in );
219             p->bytes_queued    = 0;
220             p->bytes_to_slide -= bytes_in_skip;
221             offset            += bytes_in_skip;
222             bytes_in          -= bytes_in_skip;
223         }
224     }
225 
226     if( bytes_in > 0 ) {
227         unsigned bytes_in_copy = __MIN( p->bytes_queue_max - p->bytes_queued, bytes_in );
228         memcpy( p->buf_queue + p->bytes_queued,
229                 p_buffer + offset,
230                 bytes_in_copy );
231         p->bytes_queued += bytes_in_copy;
232         offset          += bytes_in_copy;
233     }
234 
235     return offset - offset_unchanged;
236 }
237 
238 /*****************************************************************************
239  * transform_buffer: main filter loop
240  *****************************************************************************/
transform_buffer(filter_t * p_filter,uint8_t * p_buffer,size_t i_buffer,uint8_t * pout)241 static size_t transform_buffer( filter_t        *p_filter,
242                                 uint8_t         *p_buffer,
243                                 size_t           i_buffer,
244                                 uint8_t         *pout )
245 {
246     filter_sys_t *p = p_filter->p_sys;
247 
248     size_t offset_in = fill_queue( p_filter, p_buffer, i_buffer, 0 );
249     unsigned bytes_out = 0;
250     while( p->bytes_queued >= p->bytes_queue_max ) {
251         unsigned bytes_off = 0;
252 
253         // output stride
254         if( p->output_overlap ) {
255             if( p->best_overlap_offset ) {
256                 bytes_off = p->best_overlap_offset( p_filter );
257             }
258             p->output_overlap( p_filter, pout, bytes_off );
259         }
260         memcpy( pout + p->bytes_overlap,
261                 p->buf_queue + bytes_off + p->bytes_overlap,
262                 p->bytes_standing );
263         pout += p->bytes_stride;
264         bytes_out += p->bytes_stride;
265 
266         // input stride
267         memcpy( p->buf_overlap,
268                 p->buf_queue + bytes_off + p->bytes_stride,
269                 p->bytes_overlap );
270         double frames_to_slide = p->frames_stride_scaled + p->frames_stride_error;
271         unsigned frames_to_stride_whole = (int)frames_to_slide;
272         p->bytes_to_slide       = frames_to_stride_whole * p->bytes_per_frame;
273         p->frames_stride_error  = frames_to_slide - frames_to_stride_whole;
274 
275         offset_in += fill_queue( p_filter, p_buffer, i_buffer, offset_in );
276     }
277 
278     return bytes_out;
279 }
280 
281 /*****************************************************************************
282  * calculate_output_buffer_size
283  *****************************************************************************/
calculate_output_buffer_size(filter_t * p_filter,size_t bytes_in)284 static size_t calculate_output_buffer_size( filter_t        *p_filter,
285                                             size_t           bytes_in )
286 {
287     filter_sys_t *p = p_filter->p_sys;
288     size_t bytes_out = 0;
289     int bytes_to_out = bytes_in + p->bytes_queued - p->bytes_to_slide;
290     if( bytes_to_out >= (int)p->bytes_queue_max ) {
291       /* while (total_buffered - stride_length * n >= queue_max) n++ */
292       bytes_out = p->bytes_stride * ( (unsigned)(
293           ( bytes_to_out - p->bytes_queue_max + /* rounding protection */ p->bytes_per_frame )
294           / p->bytes_stride_scaled ) + 1 );
295     }
296     return bytes_out;
297 }
298 
299 /*****************************************************************************
300  * reinit_buffers: reinitializes buffers in p_filter->p_sys
301  *****************************************************************************/
reinit_buffers(filter_t * p_filter)302 static int reinit_buffers( filter_t *p_filter )
303 {
304     filter_sys_t *p = p_filter->p_sys;
305     unsigned i,j;
306 
307     unsigned frames_stride = p->ms_stride * p->sample_rate / 1000.0;
308     p->bytes_stride = frames_stride * p->bytes_per_frame;
309 
310     /* overlap */
311     unsigned frames_overlap = frames_stride * p->percent_overlap;
312     if( frames_overlap < 1 )
313     { /* if no overlap */
314         p->bytes_overlap    = 0;
315         p->bytes_standing   = p->bytes_stride;
316         p->samples_standing = p->bytes_standing / p->bytes_per_sample;
317         p->output_overlap   = NULL;
318     }
319     else
320     {
321         unsigned prev_overlap   = p->bytes_overlap;
322         p->bytes_overlap    = frames_overlap * p->bytes_per_frame;
323         p->samples_overlap  = frames_overlap * p->samples_per_frame;
324         p->bytes_standing   = p->bytes_stride - p->bytes_overlap;
325         p->samples_standing = p->bytes_standing / p->bytes_per_sample;
326         p->buf_overlap      = vlc_alloc( 1, p->bytes_overlap );
327         p->table_blend      = vlc_alloc( 4, p->samples_overlap ); /* sizeof (int32|float) */
328         if( !p->buf_overlap || !p->table_blend )
329             return VLC_ENOMEM;
330         if( p->bytes_overlap > prev_overlap )
331             memset( (uint8_t *)p->buf_overlap + prev_overlap, 0, p->bytes_overlap - prev_overlap );
332 
333         float *pb = p->table_blend;
334         float t = (float)frames_overlap;
335         for( i = 0; i<frames_overlap; i++ )
336         {
337             float v = i / t;
338             for( j = 0; j < p->samples_per_frame; j++ )
339                 *pb++ = v;
340         }
341         p->output_overlap = output_overlap_float;
342     }
343 
344     /* best overlap */
345     p->frames_search = ( frames_overlap <= 1 ) ? 0 : p->ms_search * p->sample_rate / 1000.0;
346     if( p->frames_search < 1 )
347     { /* if no search */
348         p->best_overlap_offset = NULL;
349     }
350     else
351     {
352         unsigned bytes_pre_corr = ( p->samples_overlap - p->samples_per_frame ) * 4; /* sizeof (int32|float) */
353         p->buf_pre_corr = malloc( bytes_pre_corr );
354         p->table_window = malloc( bytes_pre_corr );
355         if( ! p->buf_pre_corr || ! p->table_window )
356             return VLC_ENOMEM;
357         float *pw = p->table_window;
358         for( i = 1; i<frames_overlap; i++ )
359         {
360             float v = i * ( frames_overlap - i );
361             for( j = 0; j < p->samples_per_frame; j++ )
362                 *pw++ = v;
363         }
364         p->best_overlap_offset = best_overlap_offset_float;
365     }
366 
367     unsigned new_size = ( p->frames_search + frames_stride + frames_overlap ) * p->bytes_per_frame;
368     if( p->bytes_queued > new_size )
369     {
370         if( p->bytes_to_slide > p->bytes_queued )
371         {
372           p->bytes_to_slide -= p->bytes_queued;
373           p->bytes_queued    = 0;
374         }
375         else
376         {
377             unsigned new_queued = __MIN( p->bytes_queued - p->bytes_to_slide, new_size );
378             memmove( p->buf_queue,
379                      p->buf_queue + p->bytes_queued - new_queued,
380                      new_queued );
381             p->bytes_to_slide = 0;
382             p->bytes_queued   = new_queued;
383         }
384     }
385     p->bytes_queue_max = new_size;
386     p->buf_queue = malloc( p->bytes_queue_max );
387     if( ! p->buf_queue )
388         return VLC_ENOMEM;
389 
390     p->bytes_stride_scaled  = p->bytes_stride * p->scale;
391     p->frames_stride_scaled = p->bytes_stride_scaled / p->bytes_per_frame;
392 
393     msg_Dbg( VLC_OBJECT(p_filter),
394              "%.3f scale, %.3f stride_in, %i stride_out, %i standing, %i overlap, %i search, %i queue, %s mode",
395              p->scale,
396              p->frames_stride_scaled,
397              (int)( p->bytes_stride / p->bytes_per_frame ),
398              (int)( p->bytes_standing / p->bytes_per_frame ),
399              (int)( p->bytes_overlap / p->bytes_per_frame ),
400              p->frames_search,
401              (int)( p->bytes_queue_max / p->bytes_per_frame ),
402              "fl32");
403 
404     return VLC_SUCCESS;
405 }
406 
407 /*****************************************************************************
408  * Open: initialize as "audio filter"
409  *****************************************************************************/
Open(vlc_object_t * p_this)410 static int Open( vlc_object_t *p_this )
411 {
412     filter_t     *p_filter = (filter_t *)p_this;
413 
414     /* Allocate structure */
415     filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof(*p_sys) );
416     if( ! p_sys )
417         return VLC_ENOMEM;
418 
419     p_sys->scale             = 1.0;
420     p_sys->sample_rate       = p_filter->fmt_in.audio.i_rate;
421     p_sys->samples_per_frame = aout_FormatNbChannels( &p_filter->fmt_in.audio );
422     p_sys->bytes_per_sample  = 4;
423     p_sys->bytes_per_frame   = p_sys->samples_per_frame * p_sys->bytes_per_sample;
424 
425     msg_Dbg( p_this, "format: %5i rate, %i nch, %i bps, %s",
426              p_sys->sample_rate,
427              p_sys->samples_per_frame,
428              p_sys->bytes_per_sample,
429              "fl32" );
430 
431     p_sys->ms_stride       = var_InheritInteger( p_this, "scaletempo-stride" );
432     p_sys->percent_overlap = var_InheritFloat( p_this, "scaletempo-overlap" );
433     p_sys->ms_search       = var_InheritInteger( p_this, "scaletempo-search" );
434 
435     msg_Dbg( p_this, "params: %i stride, %.3f overlap, %i search",
436              p_sys->ms_stride, p_sys->percent_overlap, p_sys->ms_search );
437 
438     p_sys->buf_queue      = NULL;
439     p_sys->buf_overlap    = NULL;
440     p_sys->table_blend    = NULL;
441     p_sys->buf_pre_corr   = NULL;
442     p_sys->table_window   = NULL;
443     p_sys->bytes_overlap  = 0;
444     p_sys->bytes_queued   = 0;
445     p_sys->bytes_to_slide = 0;
446     p_sys->frames_stride_error = 0;
447 
448     if( reinit_buffers( p_filter ) != VLC_SUCCESS )
449     {
450         Close( p_this );
451         return VLC_EGENERIC;
452     }
453 
454     p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
455     aout_FormatPrepare(&p_filter->fmt_in.audio);
456     p_filter->fmt_out.audio = p_filter->fmt_in.audio;
457     p_filter->pf_audio_filter = DoWork;
458 
459     return VLC_SUCCESS;
460 }
461 
462 #ifdef PITCH_SHIFTER
PitchSetRateShift(filter_sys_t * p_sys,float pitch_shift)463 static inline void PitchSetRateShift( filter_sys_t *p_sys, float pitch_shift )
464 {
465     vlc_atomic_store_float( &p_sys->rate_shift,
466                             p_sys->sample_rate / powf(2, pitch_shift / 12) );
467 }
468 
PitchCallback(vlc_object_t * p_this,char const * psz_var,vlc_value_t oldval,vlc_value_t newval,void * p_data)469 static int PitchCallback( vlc_object_t *p_this, char const *psz_var,
470                           vlc_value_t oldval, vlc_value_t newval, void *p_data )
471 {
472     VLC_UNUSED( p_this );
473     VLC_UNUSED( oldval );
474     VLC_UNUSED( psz_var );
475 
476     PitchSetRateShift( p_data, newval.f_float );
477 
478     return VLC_SUCCESS;
479 }
480 
ResamplerCreate(filter_t * p_filter)481 static filter_t *ResamplerCreate(filter_t *p_filter)
482 {
483     filter_t *p_resampler = vlc_object_create( p_filter, sizeof (filter_t) );
484     if( unlikely( p_resampler == NULL ) )
485         return NULL;
486 
487     p_resampler->owner.sys = NULL;
488     p_resampler->p_cfg = NULL;
489     p_resampler->fmt_in = p_filter->fmt_in;
490     p_resampler->fmt_out = p_filter->fmt_in;
491     p_resampler->fmt_out.audio.i_rate =
492         vlc_atomic_load_float( &p_filter->p_sys->rate_shift );
493     aout_FormatPrepare( &p_resampler->fmt_out.audio );
494     p_resampler->p_module = module_need( p_resampler, "audio resampler", NULL,
495                                          false );
496 
497     if( p_resampler->p_module == NULL )
498     {
499         msg_Err( p_filter, "Could not load resampler" );
500         vlc_object_release( p_resampler );
501         return NULL;
502     }
503     return p_resampler;
504 }
505 
OpenPitch(vlc_object_t * p_this)506 static int OpenPitch( vlc_object_t *p_this )
507 {
508     int err = Open( p_this );
509     if( err )
510         return err;
511 
512     filter_t     *p_filter = (filter_t *)p_this;
513     vlc_object_t *p_aout = p_filter->obj.parent;
514     filter_sys_t *p_sys = p_filter->p_sys;
515 
516     float pitch_shift  = var_CreateGetFloat( p_aout, "pitch-shift" );
517     var_AddCallback( p_aout, "pitch-shift", PitchCallback, p_sys );
518     PitchSetRateShift( p_sys, pitch_shift );
519 
520     p_sys->resampler = ResamplerCreate(p_filter);
521     if( !p_sys->resampler )
522         return VLC_EGENERIC;
523 
524     p_filter->pf_audio_filter = DoPitchWork;
525 
526     return VLC_SUCCESS;
527 }
528 #endif
529 
Close(vlc_object_t * p_this)530 static void Close( vlc_object_t *p_this )
531 {
532     filter_t *p_filter = (filter_t *)p_this;
533     filter_sys_t *p_sys = p_filter->p_sys;
534     free( p_sys->buf_queue );
535     free( p_sys->buf_overlap );
536     free( p_sys->table_blend );
537     free( p_sys->buf_pre_corr );
538     free( p_sys->table_window );
539     free( p_sys );
540 }
541 
542 #ifdef PITCH_SHIFTER
ClosePitch(vlc_object_t * p_this)543 static void ClosePitch( vlc_object_t *p_this )
544 {
545     filter_t *p_filter = (filter_t *)p_this;
546     filter_sys_t *p_sys = p_filter->p_sys;
547     vlc_object_t *p_aout = p_filter->obj.parent;
548     var_DelCallback( p_aout, "pitch-shift", PitchCallback, p_sys );
549     var_Destroy( p_aout, "pitch-shift" );
550     module_unneed( p_sys->resampler, p_sys->resampler->p_module );
551     vlc_object_release( p_sys->resampler );
552     Close( p_this );
553 }
554 #endif
555 
556 /*****************************************************************************
557  * DoWork: filter wrapper for transform_buffer
558  *****************************************************************************/
DoWork(filter_t * p_filter,block_t * p_in_buf)559 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
560 {
561     filter_sys_t *p = p_filter->p_sys;
562 
563     if( p_filter->fmt_in.audio.i_rate == p->sample_rate )
564         return p_in_buf;
565 
566     double scale = p_filter->fmt_in.audio.i_rate / (double)p->sample_rate;
567     if( scale != p->scale ) {
568       p->scale = scale;
569       p->bytes_stride_scaled  = p->bytes_stride * p->scale;
570       p->frames_stride_scaled = p->bytes_stride_scaled / p->bytes_per_frame;
571       p->bytes_to_slide = 0;
572       msg_Dbg( p_filter, "%.3f scale, %.3f stride_in, %i stride_out",
573                p->scale,
574                p->frames_stride_scaled,
575                (int)( p->bytes_stride / p->bytes_per_frame ) );
576     }
577 
578     size_t i_outsize = calculate_output_buffer_size ( p_filter, p_in_buf->i_buffer );
579     block_t *p_out_buf = block_Alloc( i_outsize );
580     if( p_out_buf == NULL )
581     {
582         block_Release( p_in_buf );
583         return NULL;
584     }
585 
586     size_t bytes_out = transform_buffer( p_filter,
587         p_in_buf->p_buffer, p_in_buf->i_buffer,
588         p_out_buf->p_buffer );
589 
590     p_out_buf->i_buffer     = bytes_out;
591     p_out_buf->i_nb_samples = bytes_out / p->bytes_per_frame;
592     p_out_buf->i_dts        = p_in_buf->i_dts;
593     p_out_buf->i_pts        = p_in_buf->i_pts;
594     p_out_buf->i_length     = p_in_buf->i_length;
595 
596     block_Release( p_in_buf );
597     return p_out_buf;
598 }
599 
600 #ifdef PITCH_SHIFTER
DoPitchWork(filter_t * p_filter,block_t * p_in_buf)601 static block_t *DoPitchWork( filter_t * p_filter, block_t * p_in_buf )
602 {
603     filter_sys_t *p = p_filter->p_sys;
604 
605     float rate_shift = vlc_atomic_load_float( &p->rate_shift );
606 
607     /* Set matching rates for resampler's output and scaletempo's input */
608     p->resampler->fmt_out.audio.i_rate = rate_shift;
609     p_filter->fmt_in.audio.i_rate = rate_shift;
610 
611     /* Change rate, thus changing pitch */
612     p_in_buf = p->resampler->pf_audio_filter( p->resampler, p_in_buf );
613 
614     /* Change tempo while preserving shifted pitch */
615     return DoWork( p_filter, p_in_buf );
616 }
617 #endif
618