搜尋
首頁資料庫mysql教程SoundTouch音频处理库源码分析及算法提取(2)

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

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
您什麼時候應該使用複合索引與多個單列索引?您什麼時候應該使用複合索引與多個單列索引?Apr 11, 2025 am 12:06 AM

在數據庫優化中,應根據查詢需求選擇索引策略:1.當查詢涉及多個列且條件順序固定時,使用複合索引;2.當查詢涉及多個列但條件順序不固定時,使用多個單列索引。複合索引適用於優化多列查詢,單列索引則適合單列查詢。

如何識別和優化MySQL中的慢速查詢? (慢查詢日誌,performance_schema)如何識別和優化MySQL中的慢速查詢? (慢查詢日誌,performance_schema)Apr 10, 2025 am 09:36 AM

要優化MySQL慢查詢,需使用slowquerylog和performance_schema:1.啟用slowquerylog並設置閾值,記錄慢查詢;2.利用performance_schema分析查詢執行細節,找出性能瓶頸並優化。

MySQL和SQL:開發人員的基本技能MySQL和SQL:開發人員的基本技能Apr 10, 2025 am 09:30 AM

MySQL和SQL是開發者必備技能。 1.MySQL是開源的關係型數據庫管理系統,SQL是用於管理和操作數據庫的標準語言。 2.MySQL通過高效的數據存儲和檢索功能支持多種存儲引擎,SQL通過簡單語句完成複雜數據操作。 3.使用示例包括基本查詢和高級查詢,如按條件過濾和排序。 4.常見錯誤包括語法錯誤和性能問題,可通過檢查SQL語句和使用EXPLAIN命令優化。 5.性能優化技巧包括使用索引、避免全表掃描、優化JOIN操作和提升代碼可讀性。

描述MySQL異步主奴隸複製過程。描述MySQL異步主奴隸複製過程。Apr 10, 2025 am 09:30 AM

MySQL異步主從復制通過binlog實現數據同步,提升讀性能和高可用性。 1)主服務器記錄變更到binlog;2)從服務器通過I/O線程讀取binlog;3)從服務器的SQL線程應用binlog同步數據。

mysql:簡單的概念,用於輕鬆學習mysql:簡單的概念,用於輕鬆學習Apr 10, 2025 am 09:29 AM

MySQL是一個開源的關係型數據庫管理系統。 1)創建數據庫和表:使用CREATEDATABASE和CREATETABLE命令。 2)基本操作:INSERT、UPDATE、DELETE和SELECT。 3)高級操作:JOIN、子查詢和事務處理。 4)調試技巧:檢查語法、數據類型和權限。 5)優化建議:使用索引、避免SELECT*和使用事務。

MySQL:數據庫的用戶友好介紹MySQL:數據庫的用戶友好介紹Apr 10, 2025 am 09:27 AM

MySQL的安裝和基本操作包括:1.下載並安裝MySQL,設置根用戶密碼;2.使用SQL命令創建數據庫和表,如CREATEDATABASE和CREATETABLE;3.執行CRUD操作,使用INSERT,SELECT,UPDATE,DELETE命令;4.創建索引和存儲過程以優化性能和實現複雜邏輯。通過這些步驟,你可以從零開始構建和管理MySQL數據庫。

InnoDB緩衝池如何工作,為什麼對性能至關重要?InnoDB緩衝池如何工作,為什麼對性能至關重要?Apr 09, 2025 am 12:12 AM

InnoDBBufferPool通過將數據和索引頁加載到內存中來提升MySQL數據庫的性能。 1)數據頁加載到BufferPool中,減少磁盤I/O。 2)臟頁被標記並定期刷新到磁盤。 3)LRU算法管理數據頁淘汰。 4)預讀機制提前加載可能需要的數據頁。

MySQL:初學者的數據管理易用性MySQL:初學者的數據管理易用性Apr 09, 2025 am 12:07 AM

MySQL適合初學者使用,因為它安裝簡單、功能強大且易於管理數據。 1.安裝和配置簡單,適用於多種操作系統。 2.支持基本操作如創建數據庫和表、插入、查詢、更新和刪除數據。 3.提供高級功能如JOIN操作和子查詢。 4.可以通過索引、查詢優化和分錶分區來提升性能。 5.支持備份、恢復和安全措施,確保數據的安全和一致性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器