⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scaletempo.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************** * scaletempo.c: Scale audio tempo while maintaining pitch ***************************************************************************** * Copyright © 2008 the VideoLAN team * $Id$ * * Authors: Rov Juvano <rovjuvano@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_aout.h>#include <string.h> /* for memset */#include <limits.h> /* form INT_MIN *//***************************************************************************** * Module descriptor *****************************************************************************/static int  Open( vlc_object_t * );static void Close( vlc_object_t * );static void DoWork( aout_instance_t *, aout_filter_t *,                    aout_buffer_t *, aout_buffer_t * );vlc_module_begin();    set_description( N_("Scale audio tempo in sync with playback rate") );    set_shortname( N_("Scaletempo") );    set_capability( "audio filter", 0 );    set_category( CAT_AUDIO );    set_subcategory( SUBCAT_AUDIO_AFILTER );    add_integer_with_range( "scaletempo-stride", 30, 1, 2000, NULL,        N_("Stride Length"), N_("Length in milliseconds to output each stride"), true );    add_float_with_range( "scaletempo-overlap", .20, 0.0, 1.0, NULL,        N_("Overlap Length"), N_("Percentage of stride to overlap"), true );    add_integer_with_range( "scaletempo-search", 14, 0, 200, NULL,        N_("Search Length"), N_("Length in milliseconds to search for best overlap position"), true );    set_callbacks( Open, Close );vlc_module_end();/* * 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 */typedef struct aout_filter_sys_t{    /* Filter static config */    double    scale;    /* parameters */    unsigned  ms_stride;    double    percent_overlap;    unsigned  ms_search;    /* audio format */    unsigned  samples_per_frame;  /* AKA number of channels */    unsigned  bytes_per_sample;    unsigned  bytes_per_frame;    unsigned  sample_rate;    /* stride */    double    frames_stride_scaled;    double    frames_stride_error;    unsigned  bytes_stride;    double    bytes_stride_scaled;    unsigned  bytes_queue_max;    unsigned  bytes_queued;    unsigned  bytes_to_slide;    uint8_t  *buf_queue;    /* overlap */    unsigned  samples_overlap;    unsigned  samples_standing;    unsigned  bytes_overlap;    unsigned  bytes_standing;    void     *buf_overlap;    void     *table_blend;    void    (*output_overlap)( aout_filter_t *p_filter, void *p_out_buf, unsigned bytes_off );    /* best overlap */    unsigned  frames_search;    void     *buf_pre_corr;    void     *table_window;    unsigned(*best_overlap_offset)( aout_filter_t *p_filter );    /* for "audio filter" only, manage own buffers */    int       i_buf;    uint8_t  *p_buffers[2];} aout_filter_sys_t;/***************************************************************************** * best_overlap_offset: calculate best offset for overlap *****************************************************************************/static unsigned best_overlap_offset_float( aout_filter_t *p_filter ){    aout_filter_sys_t *p = p_filter->p_sys;    float *pw, *po, *ppc, *search_start;    float best_corr = INT_MIN;    unsigned best_off = 0;    unsigned i, off;    pw  = p->table_window;    po  = p->buf_overlap;    po += p->samples_per_frame;    ppc = p->buf_pre_corr;    for( i = p->samples_per_frame; i < p->samples_overlap; i++ ) {      *ppc++ = *pw++ * *po++;    }    search_start = (float *)p->buf_queue + p->samples_per_frame;    for( off = 0; off < p->frames_search; off++ ) {      float corr = 0;      float *ps = search_start;      ppc = p->buf_pre_corr;      for( i = p->samples_per_frame; i < p->samples_overlap; i++ ) {        corr += *ppc++ * *ps++;      }      if( corr > best_corr ) {        best_corr = corr;        best_off  = off;      }      search_start += p->samples_per_frame;    }    return best_off * p->bytes_per_frame;}/***************************************************************************** * output_overlap: blend end of previous stride with beginning of current stride *****************************************************************************/static void output_overlap_float( aout_filter_t   *p_filter,                                  void            *buf_out,                                  unsigned         bytes_off ){    aout_filter_sys_t *p = p_filter->p_sys;    float *pout = buf_out;    float *pb   = p->table_blend;    float *po   = p->buf_overlap;    float *pin  = (float *)( p->buf_queue + bytes_off );    unsigned i;    for( i = 0; i < p->samples_overlap; i++ ) {        *pout++ = *po - *pb++ * ( *po - *pin++ ); po++;    }}/***************************************************************************** * fill_queue: fill p_sys->buf_queue as much possible, skipping samples as needed *****************************************************************************/static size_t fill_queue( aout_filter_t *p_filter,                          uint8_t       *p_buffer,                          size_t         i_buffer,                          size_t         offset ){    aout_filter_sys_t *p = p_filter->p_sys;    unsigned bytes_in = i_buffer - offset;    size_t offset_unchanged = offset;    if( p->bytes_to_slide > 0 ) {        if( p->bytes_to_slide < p->bytes_queued ) {            unsigned bytes_in_move = p->bytes_queued - p->bytes_to_slide;            memmove( p->buf_queue,                     p->buf_queue + p->bytes_to_slide,                     bytes_in_move );            p->bytes_to_slide = 0;            p->bytes_queued   = bytes_in_move;        } else {            unsigned bytes_in_skip;            p->bytes_to_slide -= p->bytes_queued;            bytes_in_skip      = __MIN( p->bytes_to_slide, bytes_in );            p->bytes_queued    = 0;            p->bytes_to_slide -= bytes_in_skip;            offset            += bytes_in_skip;            bytes_in          -= bytes_in_skip;        }    }    if( bytes_in > 0 ) {        unsigned bytes_in_copy = __MIN( p->bytes_queue_max - p->bytes_queued, bytes_in );        memcpy( p->buf_queue + p->bytes_queued,                p_buffer + offset,                bytes_in_copy );        p->bytes_queued += bytes_in_copy;        offset          += bytes_in_copy;    }    return offset - offset_unchanged;}/***************************************************************************** * transform_buffer: main filter loop *****************************************************************************/static size_t transform_buffer( aout_filter_t   *p_filter,                                uint8_t         *p_buffer,                                size_t           i_buffer,                                uint8_t         *pout ){    aout_filter_sys_t *p = p_filter->p_sys;    size_t offset_in = fill_queue( p_filter, p_buffer, i_buffer, 0 );    unsigned bytes_out = 0;    while( p->bytes_queued >= p->bytes_queue_max ) {        unsigned bytes_off = 0;        // output stride        if( p->output_overlap ) {            if( p->best_overlap_offset ) {                bytes_off = p->best_overlap_offset( p_filter );            }            p->output_overlap( p_filter, pout, bytes_off );        }        memcpy( pout + p->bytes_overlap,                p->buf_queue + bytes_off + p->bytes_overlap,                p->bytes_standing );        pout += p->bytes_stride;        bytes_out += p->bytes_stride;        // input stride        memcpy( p->buf_overlap,                p->buf_queue + bytes_off + p->bytes_stride,                p->bytes_overlap );        double frames_to_slide = p->frames_stride_scaled + p->frames_stride_error;        unsigned frames_to_stride_whole = (int)frames_to_slide;        p->bytes_to_slide       = frames_to_stride_whole * p->bytes_per_frame;        p->frames_stride_error  = frames_to_slide - frames_to_stride_whole;        offset_in += fill_queue( p_filter, p_buffer, i_buffer, offset_in );    }    return bytes_out;}/***************************************************************************** * calculate_output_buffer_size

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -