PortAudio採集和播放音訊,實現一個雙路混音器
混音,顧名思義,就是把多個音源混合的過程,是一個很常見的應用。這兩天我也做了一個雙路混音器,當然,我沒有做多麼專業的音訊訊號處理,只是一個簡單的混音,調節各路音量,並實現了一些音效處理。主要功能有:採集硬體裝置,讀取wav檔案,播放,混音,音量調節,音訊節奏、音調的調節,wav檔案輸出。這麼多功能,我們不需要一個一個全部自己實現,有時候,藉助開源專案,尤其是比較成熟的開源專案,不但可以大大節省開發時間,還能使程式更加穩定。即便不能直接在自己的專案中使用,也能有借鑑意義。這個專案中我就使用了PortAudio,PortAudio是一個開源的、跨平臺的音訊IO庫,它主要提供了音訊採集和播放的介面,而且API非常簡單。大家可以嘗試一下。
下圖就是該專案產品截圖:
所有的功能呢,在介面上是一目瞭然了,其中有三個子視窗,是音訊資料經FFT(快速傅立葉)變換後顯示的頻譜圖,左右兩個分別是兩路音訊的,中間則是混音後的。這裡我和大家分享一下這個混音器的設計思路以及PortAudio的使用,希望有需求的朋友能夠有所借鑑。
首先是程式的邏輯架構圖
PortAudio在專案中主要負責採集硬體裝置和播放記憶體中的音訊Sample,其實在Windows上實現這種功能可以有多種方法,之前我也基於DirectShow做過,這次使用PortAudio主要也是想熟悉一下,將來如果要做其他平臺的應用時,可以直接拿來使用了。
- AudioInput的主要功能是封裝一下音訊的輸入,包括硬體採集和檔案讀取
- AudioMixer管理AudioInput,並進行音量和各種音效處理
- 鑑於檔案操作比較費時,FileWritter的操作其實是放在單獨的執行緒中進行的。
PortAudio的封裝和使用
PortAudio的API非常的簡單,基本上完成採集或播放的功能,只需要呼叫三個介面就可以了:Pa_OpenStream, Pa_StartStream, Pa_CloseStream。它們的原型如下
首先,我們需要呼叫Pa_Initialize來進行PortAudio的初始化,然後設定好Pa_OpenStream
我們只需要在回撥函式中操作inputBuffer或者outputBuffer即可,下面是我啟動前進行設定的程式碼:
1. PortAudio的採集
2. PortAudio的播放
有一點需要注意的是,framesPerBuffer的值,也就是在Pa_OpenStream中設定的引數值,這個數值就是outputBuffer或inputBuffer中音訊幀的個數,我這裡設定成了512,當然你也可以設定成其他的數值,不過不宜過小,否則會造成大量的非同步回撥,cpu是處理不過來的。這個數值再乘以你之前這隻的音訊幀Sample格式(我這裡是paFloat32)和音軌個數,就可以計算出outputBuffer或inputBuffer的大小,然後就可以操作音訊資料了,例如在採集的回撥函式中這樣使用。
memcpy(audio_data, inputBuffer, framesPerBuffer * sizeof(float)*2);
混音演算法
實話實說,這個混音演算法是我從網上找到的,不過效果還是挺不錯的,公式就是
C = A + B - (A * B >> 0x10)
A和B就是兩路不同的音訊資料,C就是混音後的音訊資料,當然,處理後,還需要對C進行防止資料溢位的處理,否則,可能會有爆音。
如果是16bit音訊資料,就是:
if (C > 32767) C = 32767; else if (C < -32768) C = -32768;
如果是float音訊資料,就是:
if (C > 1) C = 1; else if (C < -1) C = -1;
這個演算法針對的是16bit的音訊取樣資料,我實驗的結果是:對float音訊取樣資料,同樣有不錯的效果。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
haibindev.cnblogs.com,合作請聯絡QQ。(轉載請註明作者和出處)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++