IOS和Android音頻開發總結

要想本身寫一個變聲的函數或者庫出來,談何容易,因此採用了你們廣泛採用的庫SoundTouch。java

該庫能夠實現改變聲音的速度,節拍,音調(這個最重要,能夠把聲音的音調調高調低,使之變成男生女生,能夠參照湯姆貓)ios

使用的思路爲把整個庫放到不一樣平臺的底層,使用時只需包含頭文件soundtouch.h便可.c++

SoundTouch類提供了許多方法,其中最重要的就是setPitch,setRate這幾個調節聲音參數的方法,具體使用時自行設置參數。api

可是在使用前須要預先設置一下其中的幾個函數的參數以下:數組

1
2
3
4
5
6
mSoundTouchInstance->setSetting(SETTING_USE_QUICKSEEK, 0);
mSoundTouchInstance->setSetting(SETTING_USE_AA_FILTER, !(0));
mSoundTouchInstance->setSetting(SETTING_AA_FILTER_LENGTH, 32);
mSoundTouchInstance->setSetting(SETTING_SEQUENCE_MS, 40);
mSoundTouchInstance->setSetting(SETTING_SEEKWINDOW_MS, 16);
mSoundTouchInstance->setSetting(SETTING_OVERLAP_MS, 8);

 而後設置須要的參數緩存

1
2
3
4
5
mSoundTouchInstance->setChannels(2);
 
mSoundTouchInstance->setSampleRate(8000);
 
mSoundTouchInstance->setPitch(2);

這裏解釋一下音頻處理的幾個參數,很重要。網絡

聲道:channals,能夠是單聲道和雙聲道,分別對應1,2函數

採樣率:SampleRate  8000-44100不等,通常是經常使用的幾個值,安卓裏面好像44100是全部設備都支持的,因此設置成44100比較保險吧spa

每一個聲道的位數:bitsPerChannel 通常設置爲16線程

每一個幀的聲道數 ChannelsPerFrame    對於pcm數據來講,這個是1

還有幾個參數,對於安卓和ios可能說法不太同樣,以上幾個是都要用到的,比較重要,必須得掌握

 

2.Android中實現變聲

由於項目要求錄音要實時播放,因此須要採用讀取音頻數據流(PCM格式)來播放,採用的api是AudioRecorder和AudioTrack。

具體的使用方法相關資料較多,官方文檔也比較詳細。大體思路就是先初始化:

複製代碼
        //initilize
     trbusize=AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, trbusize, AudioTrack.MODE_STREAM); rebusize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT); mAudioRecord= new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDER_SAMPLERATE,AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, rebusize);
複製代碼

這裏由於不一樣設備支持的參數可能不一樣,須要是能夠寫一個循環把全部可能的參數全試一遍。

以後是錄音和播放,能夠分別放到兩個線程裏面。通常來講都是把錄音數據保存到文件中,而後再進行播放,這樣能夠應付通常的錄音需求。但不足之處在於,錄音時間久了,文件會很大,若是在網絡上實時播放的話這樣確定不行。解決方法就是將錄音的數據傳到一個緩衝區,而後播放時直接從緩衝區取走數據便可。這個緩衝區能夠考慮用循環隊列或者在java裏面能夠直接用一個LinkedList實現。

而後是變聲部分,安卓裏面要想用c++庫的話,只能經過jni來實現,能夠寫幾個函數。

複製代碼
                while(isInstancePlaying){
                    if(l<21){
                        byte[] mbyte=new byte[64];
                        mAudioRecord.read(mbyte,0,64);
                        SoundTouch.getSoundTouch().putSamples(mbyte,0,INPUT_LENGTH);
                        SoundTouch.getSoundTouch().setPitchSemiTones(pitchTone);
                        SoundTouch.getSoundTouch().receiveSamples(mbyte,INPUT_LENGTH);
                        byteArray.add(mbyte);
                        l=byteArray.size();
                    }
                    else{
                            mAudioTrack.write(byteArray.getFirst(),0,64);
                            byteArray.removeFirst();
                            l=byteArray.size();
                    }
複製代碼

代碼中有三個函數putSamples,setPitchSemiTones,receiveSamples.這三個都是native方法,在SoundTouch庫中分別經過SoundTouch類提供的對應函數實現,比較簡單,經過這幾個函數便可實現聲音的變聲。

l變量是LinkedList(代碼中的byteArray)的長度,當小於20時添加到byteArray的末尾,同時AudioTrack不斷讀取數組中的第一個元素來播放而後刪除該元素。

最後播放完要記得釋放mAudioTrack和mAudioRecorder。經過stop和release方法實現。

 

3.IOS實現變聲

 

由於本人以前沒接觸過ios因此作起來遇到了很多問題,還好最後解決了。

ios裏面的音頻處理比起安卓來講感受要麻煩一些,用到的核心api就是AudioQueue,正在使用以前必定要好好理解一下它的原理,跟安卓不一樣的是ios播放和錄音都是用的這個api。就至關於它一個東西實現了安卓中AudioRecorder和AudioTrack的功能,只不過在播放和錄音過程當中內部的流程有所變化。

核心思想:

Audio裏面有自帶的一個隊列,首先用戶建立若干個(3-6個左右都行)緩衝器用來裝填音頻數據,在自帶隊列中播放或錄音完後使用用戶自定義的回調函數進行處理,使得緩衝器可以被從新利用,而且能夠在回調函數中實現用戶自定義的一些功能,好比變聲,寫入文件等等操做。官方給了說明圖比較詳細,須要着重理解一下。

首先是錄音的流程圖:

 

 

而後是播放的流程圖:

如何變聲呢?

ios的變聲不須要安卓的jni,由於oc語言能夠和c++混編,因此這點相對來講要簡單許多。流程以下:

首先在你的程序中實例化一個SoundTouch類,而後在初始化時將它的參數設置好(setSetting),以後在上面所述的回調函數裏面就能夠將錄音獲得的數據流進行處理而後選擇保存到文件或者直接播放。思路就是這樣,可是裏面的函數的參數相對仍是比較繁瑣的,前面原理沒理解的話這邊就很難作下去了。

實時播放?

思路同Android,能夠寫一個循環隊列用來緩存音頻數據,而後邊錄音往裏面傳數據邊播放,跟安卓不一樣的是這些操做須要放到相應的回調函數裏面來實現,有個簡單的辦法是在錄音的回調函數裏面直接播放pcm數據。由於數據是一塊一塊的進來的,每使用完一次緩衝器纔會調用一次回調函數,能夠直接在回調函數裏面進行播放。

 

以上就是兩個平臺上實現錄音和實時播放的簡單介紹,這裏面的東西仍是蠻多的,值得深刻研究。

相關文章
相關標籤/搜索