Home Database Mysql Tutorial SoundTouch音频处理库源码分析及算法提取(2)

SoundTouch音频处理库源码分析及算法提取(2)

Jun 07, 2016 pm 03:31 PM
s analyze deal with extract Source code algorithm Audio

SoundTouch音频处理库初始化流程剖析 定义一个变量SoundTouch m_SoundTouch; SoundTouch的派生关系 FIFOSamplePipe-FIFOProcessor-SoundTouch (流程[1]) 因此首先构造基类FIFOSamplePipe,接着派生出FIFOProcessor,然后才以FIFOProcessor派生出SoundTouch。

SoundTouch音频处理库初始化流程剖析

定义一个变量SoundTouch m_SoundTouch;

 

SoundTouch的派生关系

FIFOSamplePipe->FIFOProcessor->SoundTouch (流程[1])

因此首先构造基类FIFOSamplePipe,接着派生出FIFOProcessor,然后才以FIFOProcessor派生出SoundTouch。这里不得不提一下老外的C++水平真的很高,在这里基本上把类的继承发挥到了极致。能够分析这样的代码简直就是一种享受。先看一下基类FIFOSamplePipe,如下定义:

class FIFOSamplePipe

{

public:

    // virtual default destructor

    virtual ~FIFOSamplePipe() {}

 

    /// Returns a pointer to the beginning of the output samples.

    /// This function is provided for accessing the output samples directly.

    /// Please be careful for not to corrupt the book-keeping!

    ///

    /// When using this function to output samples, also remember to 'remove' the

    /// output samples from the buffer by calling the

    /// 'receiveSamples(numSamples)' function

    virtual SAMPLETYPE *ptrBegin() = 0;

 

    /// Adds 'numSamples' pcs of samples from the 'samples' memory position to

    /// the sample buffer.

    virtual void putSamples(const SAMPLETYPE *samples,  ///

                            uint numSamples             ///

                            ) = 0;

 

 

    // Moves samples from the 'other' pipe instance to this instance.

    void moveSamples(FIFOSamplePipe &other  ///

         )

    {

        int oNumSamples = other.numSamples();

 

        putSamples(other.ptrBegin(), oNumSamples);

        other.receiveSamples(oNumSamples);

    };

 

    /// Output samples from beginning of the sample buffer. Copies requested samples to

    /// output buffer and removes them from the sample buffer. If there are less than

    /// 'numsample' samples in the buffer, returns all that available.

    ///

    /// /return Number of samples returned.

    virtual uint receiveSamples(SAMPLETYPE *output, ///

                                uint maxSamples                 ///

                                ) = 0;

 

    /// Adjusts book-keeping so that given number of samples are removed from beginning of the

    /// sample buffer without copying them anywhere.

    ///

    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly

    /// with 'ptrBegin' function.

    virtual uint receiveSamples(uint maxSamples   ///

 

pipe.

                                ) = 0;

 

    /// Returns number of samples currently available.

    virtual uint numSamples() const = 0;

 

    // Returns nonzero if there aren't any samples available for outputting.

    virtual int isEmpty() const = 0;

 

    /// Clears all the samples.

    virtual void clear() = 0;

}

 

这里没有实现FIFOSamplePipe类的构造函数,因此系统隐性的调用了默认的自动生成的FIFOSamplePipe()。当然他应该没有做任何的初始化,同样也不需要做任何的初始化。通过定义virtual ~FIFOSamplePipe() {}虚析构函数,使得new一个子类,例如:FIFOSamplePipe* a = new FIFOProcessor,当a销毁的时候都会执行子类FIFOProcessor的析构函数,保证不管多少层继承都会一次过全部销毁,这是作为一个基类的特点。类的继承和多态果然是C++最为强悍的一部分,有助于编写重复性很高的类。通过看这个基类的声明,我们可以留意到除了定义大多数虚函数之外,他唯独实现了moveSamples这个函数,也就是子类如果没有override moveSamples,都将调用这个方法。他做的处理也相对来说很简单,根据注释,我们不难理解,正是这个函数实现了各个派生类之间的数据共享传递的接口。

// Moves samples from the 'other' pipe instance to this instance.

moveSamples(FIFOSamplePipe &other  ///

)

{

        int oNumSamples = other.numSamples();

 

        putSamples(other.ptrBegin(), oNumSamples);

        other.receiveSamples(oNumSamples);

};

在创建SoundTouch类之前,经过(流程[1])的前面两个步骤,他们都隐形的调用了默认的析构函数,由于基类FIFOSamplePipe没有实现构造函数,我们可以默认他不做任何的初始化,然后FIFOProcessor简单的把成员变量FIFOSamplePipe *output;一个指向基类的指针赋值简单做了一下初始化,让他指向NULL。

FIFOProcessor()

{

output = NULL;

}

现在回到SoundTouch的构造函数,在构造完前面两个类之后,他终于可以调用自己的默认构造函数

SoundTouch::SoundTouch()

{

    // Initialize rate transposer and tempo changer instances

    pRateTransposer = RateTransposer::newInstance();

    pTDStretch = TDStretch::newInstance();

    setOutPipe(pTDStretch);

    rate = tempo = 0;

    virtualPitch =

    virtualRate =

    virtualTempo = 1.0;

    calcEffectiveRateAndTempo();

    channels = 0;

    bSrateSet = FALSE;

}

看一下SoundTouch类的成员变量

class SoundTouch : public FIFOProcessor

{

private:

    /// Rate transposer class instance

    class RateTransposer *pRateTransposer;

 

    /// Time-stretch class instance

    class TDStretch *pTDStretch;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualRate;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualTempo;

 

    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.

    float virtualPitch;

 

    /// Flag: Has sample rate been set?

    BOOL  bSrateSet;

 

    /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and

    /// 'virtualPitch' parameters.

    void calcEffectiveRateAndTempo();

 

protected :

    /// Number of channels

    uint  channels;

 

    /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'

    float rate;

 

    /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'

    float tempo;

...

根据构造函数他实例化pRateTransposer,pTDStretch这两个类。

首先看一下RateTransposer类的成员函数newInstance,通过一个宏定义INTEGER_SAMPLES来new一个定点还是浮点处理的类,马上就可以判断不管RateTransposerInteger还是RateTransposerFloat都应该直接从RateTransposer派生。(假设INTEGER_SAMPLES被定义)他将构造一个RateTransposerInteger。

RateTransposer *RateTransposer::newInstance()

{

#ifdef INTEGER_SAMPLES

    return ::new RateTransposerInteger;

#else

    return ::new RateTransposerFloat;

#endif

}

看一下RateTransposerInteger类的定义,不出所料果然由RateTransposer派生

class RateTransposer : public FIFOProcessor

{

protected:

...

    FIFOSampleBuffer storeBuffer;

 

    /// Buffer for keeping samples between transposing & anti-alias filter

    FIFOSampleBuffer tempBuffer;

 

    /// Output sample buffer

    FIFOSampleBuffer outputBuffer;

...

上诉两个类他们和基类之间存在这样的关系:

FIFOSamplePipe->FIFOProcessor->RateTransposer->RateTransposerInteger

这里的构造过程不同的是:RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)

RateTransposer构造函数指明了父类FIFOProcessor的构造形式FIFOProcessor(&outputBuffer)

FIFOProcessor(FIFOSamplePipe *pOutput   ///

)

{

output = pOutput;

}

RateTransposer把类成员变量outputBuffer作为传递函数参数,这里可能大家就会很奇怪,代码里面根本还没有实例化RateTransposer类,他怎么可能存在一个FIFOSampleBuffer outputBuffer;其实正是体现了c++的多态性,这里传入的实际上是一个__vfptr数组,这个数组就是指向实例化各个派生类的这个变量的指针数组。这下子明白了。__vfptr[0]不一定有值,但是__vfptr肯定是一个存在的值。构造完FIFOProcessor,此时要构造RateTransposer,他有三个FIFOSampleBuffer类定义。

...

class FIFOSampleBuffer : public FIFOSamplePipe

...

与基类的继承关系

FIFOSamplePipe->FIFOSampleBuffer

/// Constructor

FIFOSampleBuffer(int numChannels = 2     ///

                                              ///

);

他没有定义不带参的构造函数,因此这个带参数的构造函数将以默认的方式给调用

FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)

{

    assert(numChannels > 0);

    sizeInBytes = 0; // reasonable initial value

    buffer = NULL;

    bufferUnaligned = NULL;

    samplesInBuffer = 0;

    bufferPos = 0;

    channels = (uint)numChannels;

    ensureCapacity(32);     // allocate initial capacity

}

FIFOSampleBuffer的构造函数将被调用三次。

现在终于可以执行RateTransposer的构造函数

// Constructor

RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)

{

    numChannels = 2;

    bUseAAFilter = TRUE;

    fRate = 0;

 

    // Instantiates the anti-alias filter with default tap length

    // of 32

    pAAFilter = new AAFilter(32);

}

首先看一下AAFilter的相关定义

class AAFilter

{

protected:

    class FIRFilter *pFIR;

    /// Low-pass filter cut-off frequency, negative = invalid

    double cutoffFreq;

    /// num of filter taps

    uint length;

    /// Calculate the FIR coefficients realizing the given cutoff-frequency

    void calculateCoeffs();

public:

    AAFilter(uint length);

    ~AAFilter();

    /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling

    /// frequency (nyquist frequency = 0.5). The filter will cut off the

    /// frequencies than that.

    void setCutoffFreq(double newCutoffFreq);

    /// Sets number of FIR filter taps, i.e. ~filter complexity

    void setLength(uint newLength);

    uint getLength() const;

    /// Applies the filter to the given sequence of samples.

    /// Note : The amount of outputted samples is by value of 'filter length'

    /// smaller than the amount of input samples.

    uint evaluate(SAMPLETYPE *dest,

                  const SAMPLETYPE *src,

                  uint numSamples,

                  uint numChannels) const;

};

在其构造函数中初始化了一个指向class FIRFilter的指针

AAFilter::AAFilter(uint len)

{

    pFIR = FIRFilter::newInstance();

    cutoffFreq = 0.5;

    setLength(len);

}

首先我们看看FIRFilter类成员函数newInstance(),嘿嘿,在这里我们发现了一个非常有用的函数detectCPUextensions();通过这个函数我们可以判断cpu到底支持什么类型的多媒体指令集。根据注释我们也可以很快理解。detectCPUextensions收藏了。他的实现就在Cpu_detect_x86_win.cpp的实现中。美中不足的是,他只能检测x86结构体系的CPU。可能我多想了。根据本人电脑的配置(采用的赛扬cpu),所以只支持mmx指令。

FIRFilter * FIRFilter::newInstance()

{

    uint uExtensions;

    uExtensions = detectCPUextensions();

    // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU

#ifdef ALLOW_MMX

    // MMX routines available only with integer sample types

    if (uExtensions & SUPPORT_MMX)

    {

        return ::new FIRFilterMMX;

    }

    else

#endif // ALLOW_MMX

#ifdef ALLOW_SSE

    if (uExtensions & SUPPORT_SSE)

    {

        // SSE support

        return ::new FIRFilterSSE;

    }

    else

#endif // ALLOW_SSE

#ifdef ALLOW_3DNOW

    if (uExtensions & SUPPORT_3DNOW)

    {

        // 3DNow! support

        return ::new FIRFilter3DNow;

    }

    else

#endif // ALLOW_3DNOW

    {

        // ISA optimizations not supported, use plain C version

        return ::new FIRFilter;

    }

}

为此他将通过这个判断构造返回一个FIRFilterMMX类

if (uExtensions & SUPPORT_MMX)

    {

        return ::new FIRFilterMMX;

    }

查看FIRFilterMMX的类定义class FIRFilterMMX : public FIRFilter,他从FIRFilter派生。成员函数uint FIRFilterMMX::evaluateFilterStereo引起了我的高度注意,主要的算法采用MMX指令集来完成某些声音计算。这个就是我们需要的Rate的核心算法。不同指令集的实现,可以参考FIRFilter3DNow,FIRFilterSSE,默认是FIRFilter的evaluateFilterStereo函数的实现。

// mmx-optimized version of the filter routine for stereo sound

uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const

{

    // Create stack copies of the needed member variables for asm routines :

    uint i, j;

    __m64 *pVdest = (__m64*)dest;

 

    if (length

 

    for (i = 0; i

    {

        __m64 accu1;

        __m64 accu2;

        const __m64 *pVsrc = (const __m64*)src;

        const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;

 

        accu1 = accu2 = _mm_setzero_si64();

        for (j = 0; j

        {

            __m64 temp1, temp2;

 

            temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]);  // = l2 l0 r2 r0

            temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]);  // = l3 l1 r3 r1

 

            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0]));  // += l2*f2+l0*f0

 

r2*f2+r0*f0

            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1]));  // += l3*f3+l1*f1

 

r3*f3+r1*f1

 

            temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]);  // = l4 l2 r4 r2

 

            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0]));  // += l3*f2+l1*f0

 

r3*f2+r1*f0

            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1]));  // += l4*f3+l2*f1

 

r4*f3+r2*f1

 

            // accu1 += l2*f2+l0*f0 r2*f2+r0*f0

            //       += l3*f3+l1*f1 r3*f3+r1*f1

 

            // accu2 += l3*f2+l1*f0 r3*f2+r1*f0

            //          l4*f3+l2*f1 r4*f3+r2*f1

 

            pVfilter += 2;

            pVsrc += 2;

        }

        // accu >>= resultDivFactor

        accu1 = _mm_srai_pi32(accu1, resultDivFactor);

        accu2 = _mm_srai_pi32(accu2, resultDivFactor);

 

        // pack 2*2*32bits => 4*16 bits

        pVdest[0] = _mm_packs_pi32(accu1, accu2);

        src += 4;

        pVdest ++;

    }

 

   _m_empty();  // clear emms state

 

    return (numSamples & 0xfffffffe) - length;

}

因此,如果把SoundTouch移植到arm等没有多媒体指令集的CPU时,应使用FIRFilter的evaluateFilterStere函数。执行完这里,终于可以真正意义上构造我们的RateTransposerInteger()。在构造函数中:

RateTransposerInteger::RateTransposerInteger() : RateTransposer()

{

    // Notice: use local function calling syntax for sake of clarity,

    // to indicate the fact that C++ constructor can't call virtual functions.

    RateTransposerInteger::resetRegisters();

    RateTransposerInteger::setRate(1.0f);

}进行了一些必要的初始化。至此pRateTransposer = RateTransposer::newInstance();实例化完毕。至于pTDStretch = TDStretch::newInstance();下回分晓。

 

 

http://blog.csdn.net/suhetao/archive/2010/08/28/5845667.aspx

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

The operation process of WIN10 service host occupying too much CPU The operation process of WIN10 service host occupying too much CPU Mar 27, 2024 pm 02:41 PM

1. First, we right-click the blank space of the taskbar and select the [Task Manager] option, or right-click the start logo, and then select the [Task Manager] option. 2. In the opened Task Manager interface, we click the [Services] tab on the far right. 3. In the opened [Service] tab, click the [Open Service] option below. 4. In the [Services] window that opens, right-click the [InternetConnectionSharing(ICS)] service, and then select the [Properties] option. 5. In the properties window that opens, change [Open with] to [Disabled], click [Apply] and then click [OK]. 6. Click the start logo, then click the shutdown button, select [Restart], and complete the computer restart.

CLIP-BEVFormer: Explicitly supervise the BEVFormer structure to improve long-tail detection performance CLIP-BEVFormer: Explicitly supervise the BEVFormer structure to improve long-tail detection performance Mar 26, 2024 pm 12:41 PM

Written above & the author’s personal understanding: At present, in the entire autonomous driving system, the perception module plays a vital role. The autonomous vehicle driving on the road can only obtain accurate perception results through the perception module. The downstream regulation and control module in the autonomous driving system makes timely and correct judgments and behavioral decisions. Currently, cars with autonomous driving functions are usually equipped with a variety of data information sensors including surround-view camera sensors, lidar sensors, and millimeter-wave radar sensors to collect information in different modalities to achieve accurate perception tasks. The BEV perception algorithm based on pure vision is favored by the industry because of its low hardware cost and easy deployment, and its output results can be easily applied to various downstream tasks.

Implementing Machine Learning Algorithms in C++: Common Challenges and Solutions Implementing Machine Learning Algorithms in C++: Common Challenges and Solutions Jun 03, 2024 pm 01:25 PM

Common challenges faced by machine learning algorithms in C++ include memory management, multi-threading, performance optimization, and maintainability. Solutions include using smart pointers, modern threading libraries, SIMD instructions and third-party libraries, as well as following coding style guidelines and using automation tools. Practical cases show how to use the Eigen library to implement linear regression algorithms, effectively manage memory and use high-performance matrix operations.

Explore the underlying principles and algorithm selection of the C++sort function Explore the underlying principles and algorithm selection of the C++sort function Apr 02, 2024 pm 05:36 PM

The bottom layer of the C++sort function uses merge sort, its complexity is O(nlogn), and provides different sorting algorithm choices, including quick sort, heap sort and stable sort.

Can artificial intelligence predict crime? Explore CrimeGPT's capabilities Can artificial intelligence predict crime? Explore CrimeGPT's capabilities Mar 22, 2024 pm 10:10 PM

The convergence of artificial intelligence (AI) and law enforcement opens up new possibilities for crime prevention and detection. The predictive capabilities of artificial intelligence are widely used in systems such as CrimeGPT (Crime Prediction Technology) to predict criminal activities. This article explores the potential of artificial intelligence in crime prediction, its current applications, the challenges it faces, and the possible ethical implications of the technology. Artificial Intelligence and Crime Prediction: The Basics CrimeGPT uses machine learning algorithms to analyze large data sets, identifying patterns that can predict where and when crimes are likely to occur. These data sets include historical crime statistics, demographic information, economic indicators, weather patterns, and more. By identifying trends that human analysts might miss, artificial intelligence can empower law enforcement agencies

Learn how to handle special characters and convert single quotes in PHP Learn how to handle special characters and convert single quotes in PHP Mar 27, 2024 pm 12:39 PM

In the process of PHP development, dealing with special characters is a common problem, especially in string processing, special characters are often escaped. Among them, converting special characters into single quotes is a relatively common requirement, because in PHP, single quotes are a common way to wrap strings. In this article, we will explain how to handle special character conversion single quotes in PHP and provide specific code examples. In PHP, special characters include but are not limited to single quotes ('), double quotes ("), backslash (), etc. In strings

Improved detection algorithm: for target detection in high-resolution optical remote sensing images Improved detection algorithm: for target detection in high-resolution optical remote sensing images Jun 06, 2024 pm 12:33 PM

01 Outlook Summary Currently, it is difficult to achieve an appropriate balance between detection efficiency and detection results. We have developed an enhanced YOLOv5 algorithm for target detection in high-resolution optical remote sensing images, using multi-layer feature pyramids, multi-detection head strategies and hybrid attention modules to improve the effect of the target detection network in optical remote sensing images. According to the SIMD data set, the mAP of the new algorithm is 2.2% better than YOLOv5 and 8.48% better than YOLOX, achieving a better balance between detection results and speed. 02 Background & Motivation With the rapid development of remote sensing technology, high-resolution optical remote sensing images have been used to describe many objects on the earth’s surface, including aircraft, cars, buildings, etc. Object detection in the interpretation of remote sensing images

How to set up PPT to automatically play multiple audios How to set up PPT to automatically play multiple audios Mar 26, 2024 pm 06:21 PM

1. Open PPT, click [Insert] on the menu bar, and then click [Audio]. 2. In the file selection box that opens, select the first audio file you want to insert. 3. After the insertion is successful, a speaker icon will be displayed in the PPT to represent the file just inserted. You can play and listen to it and adjust the volume to control its volume during the PPT screening process. 4. Follow the same method and insert the second audio file. At this time, two speaker icons will be displayed in the PPT, representing two audio files respectively. 5. Click to select the first audio file icon, and then click the [Play] menu. 6. In Start in the toolbar, select [Play Across Slides] to set this audio to play in every slide without human intervention. 7. Follow the steps in step 6

See all articles