原因
OpenSL ES 學習到如今已經知道 OpenSL ES 不只能播放和錄製PCM音頻數據,還能改變聲音大小、設置左聲道或右聲道播放、還能變速播放,可謂是播放音頻的王者。可是變速有一點很差的就是,雖然播放音頻的速度變了,可是相應的音調也隨之變了,這樣的用戶體驗就不那麼好了。因此就想到了用開源的SoundTouch來實現PCM音頻變速和變調,OpenSL ES只是單純的播放PCM數據就能夠了。html
實現
一、移植SoundTouch(Android)
下載SoundTouch源碼,當前最新是:v2.0.1git
在項目jni文件夾中建立include和SoundTouch文件夾,並把下載好的SoundTouch裏面的include和SoundTouch的源碼拷貝進去就能夠了,目錄結構以下:github
二、用SoundTouch轉碼PCM源文件
由於SoundTouch默認是float(32bit)格式的數據,這裏須要先改爲short(16bit)的格式。打開STTypes.h文件,修改以下代碼:緩存
再註釋掉下面這句,否則編譯不經過(for x86模擬器):函數
這樣SoundTouch裏面處理PCM數據就是用的16bit的數據了。學習
三、SoundTouch使用流程
3.1 添加命名空間,並建立SoundTouch指針變量
using namespace soundtouch; SoundTouch *soundTouch;
3.2 設置SoundTouch參數
soundTouch = new SoundTouch(); soundTouch->setSampleRate(44100);//設置採樣率,此處爲44100,根據實際狀況可變 soundTouch->setChannels(2);//聲道,此處爲立體聲 soundTouch->setPitch(1);//變調不變速,如0.五、1.0、1.5等 soundTouch->setTempo(1);//變速不變調,如0.五、1.0、2.0等
3.3 向SoundTouch中傳入獲取到的PCM數據,使用:putSamples函數
size = fread(pcm_buffer, 1, 4096 * 2, pcmFile); soundTouch->putSamples((const SAMPLETYPE *) pcm_buffer, size / 4);
這裏,pcm_buffer是u_int16_t *類型的,也就是說和SoundTouch處理的PCM數據位數是一致的(16bit),因此能夠直接傳入SoundTouch中。putSamples的第一個參數就是PCM數據指針,第二個參數是採樣點的個數,因爲是2聲道16bit(2byte),因此PCM數據的採樣點個數爲:num = 大小(size)/ (2 * 2)。ui
3.4 獲取SoundTouch輸出的PCM數據:使用receiveSamples函數
num = soundTouch->receiveSamples(sd_buffer, size / 4);
這裏,receiveSamples的第一個參數是SoundTouch(變速或變調)處理後的PCM數據存放的內存地址,第二個參數是可能的最大采樣個數,能夠和putSamples保持一致,其中sd_buffer是SAMPLETYPE * 類型的,記得要提早分配好內存大小,最後返回值就是SoundTouch處理後的PCM裏面所包含的採樣個數,因爲可能有緩存,因此應循環讀取receiveSamples,直到返回值爲0爲止。url
3.5 OpenSL ES播放SoundTouch處理後的PCM音頻數據
(*pcmBufferQueue)->Enqueue(pcmBufferQueue, sd_buffer, size * 4);
因爲size是採樣個數,因此sd_buffer的大小是:size * 2(聲道) * 2(16bit==2字節)。spa
這樣,咱們聽到的聲音就是經過SoundTouch轉碼事後的了,如:變速不變調,變調不變速,變速又變調均可以本身設置。.net
思惟發散
FFmpeg解碼獲得的PCM數據(uint_8 *)利用SoundTouch轉碼
這裏要處理的就是把uint_8 *(8bit)的數據轉換成short(16bit)的數據格式。這裏其實就是作bit的位運算,原理以下如:
轉換代碼以下:
for (int i = 0; i < size / 2 + 1; i++) { sd_buffer[i] = (pcm_buffer[i * 2] | (pcm_buffer[i * 2 + 1] << 8)); } soundTouch->putSamples((const SAMPLETYPE *) pcm_buffer, size / 4);
後續操做和16bit的同樣不變。
總結
雖然是簡單的移植SoundTouch到Android來播放PCM數據,可是仍是讓咱們瞭解到了數據在內存中怎麼排列的,而後能夠怎麼操做最小單位的bit來達到咱們的要求。
參考資料
OpenSL ES利用SoundTouch實現PCM音頻的變速和變調