使用SoudTouch實現(xiàn)變速變調(diào)

  1. 聲明SoundTouch對象和內(nèi)存變量,根據(jù)聲道數(shù)和采樣率初始化對象和內(nèi)存
    SoundTouch *soundTouch = NULL;
    SAMPLETYPE *sampleBuffer = NULL;
    //采樣率
    int sample_rate=44100;
    //聲道數(shù)
    int channels =2;
    //變調(diào)
    float pitch= 1.0f;
    //變數(shù)
    float speed= 1.0f;
    //采樣位數(shù) SoudTouch最低支持16bit浸遗,所以使用16bit的來播放
    int bits= 16;
     //每秒理論PCM大小
    int BUFF_SIZE =sample_rate * channels * bits/8;
    
   
    sampleBuffer = static_cast<SAMPLETYPE *>(malloc(BUFF_SIZE));
    soundTouch = new SoundTouch();
    soundTouch->setSampleRate(sample_rate);
    soundTouch->setChannels(channels);
    soundTouch->setPitch(pitch);
    soundTouch->setTempo(speed);


  1. PCM數(shù)據(jù)給SoundTouch處理
    //采樣個數(shù),具體怎么獲取看具體情況
    int nb=0;
    //示例1 :文件讀取
    int size = fread();
    nb = size/channels;
    //示例2 :ffmpeg解碼
    int nb = swr_convert();
    
    //最大采樣數(shù)
   
    int maxSamples = BUFF_SIZE / channels; 
    
    //處理數(shù)據(jù)
    soundTouch->putSamples(sampleBuffer, nb);
    //得到數(shù)據(jù)到sampleBuffer
    int num = soundTouch->receiveSamples(sampleBuffer, maxSamples);

  1. 設(shè)置變速和變調(diào)
    soundTouch->setPitch(1.0); //變調(diào)
    soundTouch->setTempo(1.5);//變速

  1. SoudTouch選擇處理數(shù)據(jù)是16bit還是32bit,在STTypes.h里面找到
 #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
       
        /// Choose either 32bit floating point or 16bit integer sampletype
        /// by choosing one of the following defines, unless this selection 
        /// has already been done in some other file.
        ////
        /// Notes:
        /// - In Windows environment, choose the sample format with the
        ///   following defines.
        /// - In GNU environment, the floating point samples are used by 
        ///   default, but integer samples can be chosen by giving the 
        ///   following switch to the configure script:
        ///       ./configure --enable-integer-samples
        ///   However, if you still prefer to select the sample format here 
        ///   also in GNU environment, then please #undef the INTEGER_SAMPLE
        ///   and FLOAT_SAMPLE defines first as in comments above.
        //#define SOUNDTOUCH_INTEGER_SAMPLES     1    //< 16bit integer samples
        #define SOUNDTOUCH_FLOAT_SAMPLES       1    //< 32bit float samples
     
    #endif

根據(jù)你的類型注釋選擇對應(yīng)的宏定義即可

  1. ffmpeg里面使用的時候需要注意的點:因為FFmpeg解碼出來的PCM數(shù)據(jù)是8bit (uint8)的,而SoundTouch中最低
    16bit( 16bit integer samples)垫挨,所以我們需要將8bit的數(shù)據(jù)轉(zhuǎn)換成16bit
    后再給SoundTouch處理喳篇。

8bit->16bit處理方式:

SAMPLETYPE *sampleBuffer=NULL ;
uint8_t *out_buffer = NULL;

//....初始化等

//獲取音頻數(shù)據(jù)到out_buffer
int data_size = resampleAudio(reinterpret_cast<void **>(&out_buffer));
for(int i = 0; i < data_size / 2 + 1; i++)
{
    sampleBuffer[i] = (buffer[i * 2] | ((buffer[i * 2 + 1]) << 8));
}

  1. 官方示例,將一個文件變速變調(diào)轉(zhuǎn)為另外一個文件
static void
_processFile(SoundTouch *pSoundTouch, const float pitch, const float tempo, const char *inFileName,
             const char *outFileName) {

    SoundTouch *pSoundTouch = new SoundTouch();
    
    //設(shè)置音調(diào)
    pSoundTouch->setPitch(pitch);
    //設(shè)置音速
    pSoundTouch->setTempo(tempo);
    
    int nSamples;//采樣率
    int nChannels;//聲道
    int buffSizeSamples;//每一次緩沖大小
    SAMPLETYPE sampleBuffer[BUFF_SIZE];//緩沖

    // open input file
    WavInFile inFile(inFileName);
    int sampleRate = inFile.getSampleRate();
    int bits = inFile.getNumBits();
    nChannels = inFile.getNumChannels();

    // create output file
    WavOutFile outFile(outFileName, sampleRate, bits, nChannels);

    pSoundTouch->setSampleRate(sampleRate);
    pSoundTouch->setChannels(nChannels);

    assert(nChannels > 0);
    buffSizeSamples = BUFF_SIZE / nChannels;

    // Process samples read from the input file
    while (inFile.eof() == 0) {
        int num;

        // Read a chunk of samples from the input file
        num = inFile.read(sampleBuffer, BUFF_SIZE);
        nSamples = num / nChannels;

        // Feed the samples into SoundTouch processor
        pSoundTouch->putSamples(sampleBuffer, nSamples);

        // Read ready samples from SoundTouch processor & write them output file.
        // NOTES:
        // - 'receiveSamples' doesn't necessarily return any samples at all
        //   during some rounds!
        // - On the other hand, during some round 'receiveSamples' may have more
        //   ready samples than would fit into 'sampleBuffer', and for this reason
        //   the 'receiveSamples' call is iterated for as many times as it
        //   outputs samples.
        do {
            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
            outFile.write(sampleBuffer, nSamples * nChannels);
        } while (nSamples != 0);
    }

    // Now the input file is processed, yet 'flush' few last samples that are
    // hiding in the SoundTouch's internal processing pipeline.
    pSoundTouch->flush();
    do {
        nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
        outFile.write(sampleBuffer, nSamples * nChannels);
    } while (nSamples != 0);

    delete (pSoundTouch);
}

  1. ffmpeg示例

    SoundTouch *soundTouch = NULL;
    SAMPLETYPE *sampleBuffer = NULL;
    //采樣率
    int sample_rate=44100;
    //聲道數(shù)
    int channels =2;
    //變調(diào)
    float pitch= 1.0f;
    //變數(shù)
    float speed= 1.0f;
    //采樣位數(shù) SoudTouch最低支持16bit炎滞,所以使用16bit的來播放
    int bits= 16;
     //每秒理論PCM大小
    int BUFF_SIZE =sample_rate * channels * bits/8;
    
   
    sampleBuffer = static_cast<SAMPLETYPE *>(malloc(BUFF_SIZE));
    soundTouch = new SoundTouch();
    soundTouch->setSampleRate(sample_rate);
    soundTouch->setChannels(channels);
    soundTouch->setPitch(pitch);
    soundTouch->setTempo(speed);


    //獲取SoundTouch處理的數(shù)據(jù)
    int WlAudio::getSoundTouchData() {
        int maxSamples = BUFF_SIZE / channels;
        while (playstatus != NULL && !playstatus->exit) {
            out_buffer = NULL;
            if (finished) {
                finished = false;
                //獲取pcm數(shù)據(jù)到out_buffer
                data_size = resampleAudio(reinterpret_cast<void **>(&out_buffer));
                if (data_size > 0) {
                    for (int i = 0; i < data_size / 2 + 1; i++) {
                        //解碼的數(shù)據(jù)是8bit的
                        //8bit->16bit
                        sampleBuffer[i] = (out_buffer[i * 2] | ((out_buffer[i * 2 + 1]) << 8));
                    }
                    //nb 表示采樣個數(shù)  在resampleAudio里面解碼的時候通過swr_convert返回值回去
                    soundTouch->putSamples(sampleBuffer, nb);
                    //獲取處理后的數(shù)據(jù)  到sampleBuffer
                    num = soundTouch->receiveSamples(sampleBuffer,maxSamples);
                } else {
                    soundTouch->flush();
                }
            }
            if (num == 0) {
                finished = true;
                continue;
            } else {
                if (out_buffer == NULL) {
                    num = soundTouch->receiveSamples(sampleBuffer, maxSamples);
                    if (num == 0) {
                        finished = true;
                        continue;
                    }
                }
                return num;
            }
        }
        return 0;
    }
    
    //OpenSLES播放數(shù)據(jù)
    
    int buffersize = wlAudio->getSoundTouchData();
    if (buffersize > 0) {
    //兩個8bit->一個16bit     轉(zhuǎn)換為char*是為了都轉(zhuǎn)換成字節(jié)來處理
     (*wlAudio->pcmBufferQueue)->Enqueue(wlAudio->pcmBufferQueue,
                                                    (char *) wlAudio->sampleBuffer, buffersize * nChannels * 2 );
     }


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚜迅,一起剝皮案震驚了整個濱河市舵匾,隨后出現(xiàn)的幾起案子俊抵,更是在濱河造成了極大的恐慌谁不,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徽诲,死亡現(xiàn)場離奇詭異刹帕,居然都是意外死亡,警方通過查閱死者的電腦和手機谎替,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門偷溺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钱贯,你說我怎么就攤上這事挫掏。” “怎么了秩命?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵尉共,是天一觀的道長。 經(jīng)常有香客問我弃锐,道長袄友,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任霹菊,我火速辦了婚禮剧蚣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旋廷。我一直安慰自己鸠按,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布饶碘。 她就那樣靜靜地躺著待诅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熊镣。 梳的紋絲不亂的頭發(fā)上卑雁,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天募书,我揣著相機與錄音,去河邊找鬼测蹲。 笑死莹捡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扣甲。 我是一名探鬼主播篮赢,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琉挖!你這毒婦竟也來了启泣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤示辈,失蹤者是張志新(化名)和其女友劉穎寥茫,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矾麻,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡纱耻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了险耀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄喘。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甩牺,靈堂內(nèi)的尸體忽然破棺而出蘑志,到底是詐尸還是另有隱情,我是刑警寧澤贬派,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布急但,位于F島的核電站,受9級特大地震影響赠群,放射性物質(zhì)發(fā)生泄漏羊始。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一查描、第九天 我趴在偏房一處隱蔽的房頂上張望突委。 院中可真熱鬧,春花似錦冬三、人聲如沸匀油。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敌蚜。三九已至,卻和暖如春窝爪,著一層夾襖步出監(jiān)牢的瞬間弛车,已是汗流浹背齐媒。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纷跛,地道東北人喻括。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像贫奠,于是被迫代替她去往敵國和親唬血。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容