一、最簡單的混音演算法 現在一般的軟體混音演算法是對輸入的音訊資料進行線性疊加, 即:
(1) 或者疊加以後再取平均值: 
(2) 其中, m 為輸入音訊流的個數, n 為一幀的樣本數目, ·
[i] 為一幀中的第i 個樣本, ·[j] 為第j 個音訊流, 所以, output[i] 為混音後的一幀中第i 個樣本, input[j][i] 為第j 個輸入音訊流當前幀的第i 個樣本(若經過編碼則輸入音訊流應在混音前通過解碼等還原成線性的PCM音訊流).通常的語音資料為16 bit(或者更少, 如8 bit), 即可以用C 語言中的short 類型表示, 其取值範圍是32768 ≤ 採樣值≤ 32767, 可以預想到多個音訊流直接線性疊加以後就有可能溢出, 所以式(1) 最後的結果可能會有溢出, 產生噪音.兩個連續平滑的波形疊加, 其結果也應該是平滑的. 所以產生噪音的地方就是由疊加溢出的地方引入的.我們需要採用濾波來處理這些溢出部分, 改善由於溢出所造成的品質下降.為了解決溢出的問題, 一個常用的方法就是使用更多的位數來表示音訊資料的一個樣本, 在混音完畢以後,再使用一些演算法來降低其振幅, 使其分佈在16 bit 所能表示的範圍之內, 這種方法叫做歸一化(Normalize). 通常使用32 bit 來表示線性疊加以後的資料, 也就是C 語言中的int 類型, 實現簡單, 運算也比較快, 更能滿足很多路音訊同時進行混音的需要. 式(2)對疊加的和值作平均, 解決了溢出的問題, 但是混音以後的聲音會總體衰減,特別是某一路音訊流的能量與其他路音訊流的能量反差很大的情況下, 音量非常小, 效果非常不理想. 進行濾波處理的另外一種常用方法就是“箝位”, 當發生上溢時, 箝位以後的值為所能表示的最大值, 當發生下溢時, 箝位後的值為所能表示的最小值, 如式(3) 所示: 
(3) 其中, sample 為疊加以後的樣本值, 為 32 bit, MAX 是最大輸出值, 這裡為32767, MIN 為最小輸出值, 為32768. 
現在很多現有的論文和系統都是採用箝位方法, 因為實現簡單, 快速, 效率很高. 但是可以看出, 這種箝位方法相當於在最大和最小的臨界值處切強行切斷波形, 非常生硬, 會造成較大的波形失真, 聽覺上引起如嘈雜, 出現突發刺耳的爆破音等.採用時域疊加作為基本的處理手段, 由於數位音訊信號存在量化上限和下限的問題,則因疊加運算肯定會造成結果溢出. 通常的處理手段是進行溢出檢測, 然後再進行飽和運算(如 4 式的方法), 即超過上限的結果被置為上限值, 超過下限的值置為下限值. 這種運算本身破壞了語音信號原有的時域特徵, 從而引入了雜訊. 這就是出現爆破聲和語音不連續現象的原因. 同時, 隨著參與混音的人數增加, 出現溢出的頻率也不斷上升, 所以這類方法存在一個上限, 而且這個上限值很低, 實驗證明, 採用這種時域直接疊加的方式進行混音, 一般不能突破 4 路輸入音訊流的限制, 否則將無法分辨語音流的內容了.


二、改進的混音演算法 混音的時候, 還需要遮罩某一路的本地音訊資料, 這樣就不會聽到本地的聲音, 只能聽到其他 n 1 路的聲音, 也就是說, 對於第 t 路音訊, 要發送給這個終端的混音後的資料如式(4):

(4) 以下提出的演算法主要思想就是使用一個衰減因數, 對音訊資料進行衰減, 衰減因數會隨著資料而變化. 
當溢出時, 衰減因數比較小, 使溢出的音訊資料衰減以後處於臨界值以內, 當沒有溢出時, 衰減因數會慢慢增加, 儘量保持資料的平滑變化. 而不是對於整幀使用同一個衰減因數來進行, 這是不同于式(2) 和式(3) 的地方, 既保證了整體的聲強不至於衰減太快, 又保證了較小的失真度. 演算法如下所述:
1. f 初始化為1.
2. 對於一幀中的樣本按連續處理: (a) output[i] = mixing[i] × f. (b) 如果output[i] > MAX, 求得最大的 f0 滿足 output[i] × f0 < MAX, 然後 f = f0, output[i] = MAX. (c) 如果output[i] < MIN, 求得最大的 f0 滿足 output[i]×f0 > MIN, 然後 f = f0, output[i] = MIN.
3. 如果f < 1, 則f = f + STEPSIZE. 繼續處理下一幀, 轉2. 其中f 為衰減因數, f0 為新的衰減因數; mixing[] 為所有音訊流的某一幀線性疊加值, 實際實現的時候如式(4) 所示; output[] 為歸一化以後的輸出幀. MAX 為正的最大值; MIN 為負的最大值. STEPSIZE 為f 變化的步長, 通常取為 (1 f)/16 或者 (1 f)/32. 特別的, 就是在衰減以後的值溢出的情況下, 求新的衰減因數 f0 的方法不同, 新的 f0 需要滿足 output[i] × f0 < MAX 或者 output[i] × f0 > MIN, 而不是直接使用mixing[i]. 也就是說, 使用衰減以後的值output[i] 來計算f0, 而不是原始值mixing[i], 這樣將使得衰減因數的變化更為平滑. 用數學來表達, S 為溢出的一個樣本值, 在S × f 仍然溢出的情況下, 可以比較一下計算出來的新衰減因數的大小:假設是上溢, forig 是原始演算法計算出的新的衰減因數, 則f`orig < (MAX/S) , 我們改進的演算法得出的新衰減因數 f`new < (MAX/(S×f)) , 因為 S > (S × f), 所以(MAX/S) < (MAX/(S×f)) , 那麼 f`new 很大程度上要大於f`orig. 衰減因數大了(更接近1), 相鄰的資料變化不會特別大, 所以跳躍的現象不會特別明顯. 上述改進過的混音方案在實測中,與常規的混音演算法(直接線性疊加的方式)比較, 常規演算法在混入 4 路音訊流的結果, 已經明顯聽到背景雜音, 波形會突變失真, 出現比較輕微的爆破音, 少量出現語音不可以辨認的情況; 如果混入 5 路或者 5 路以上的音訊流, 則輸出的音訊流品質已經不能從聽覺上接受, 語聲模糊並且爆破音明顯, 噪音大, 難以辨別語音內容. 採用衰減因數的方式進行調整以後, 混入 4 路音訊流從聽覺上基本感覺不到背景雜音, 混入 5 路的情況下, 仍然能清晰辨別各路的語音內容, 不出現爆破音; 混入 6 路到 9 路的情況下仍然能保證語音品質, 不會發生突變的爆破音, 能夠滿足視訊會議的要求. 從演算法執行效率上看, 與常規的混音演算法比較, 其時間複雜度並沒有增加而具有同等的時間複雜度, 只是調和係數法在計算過程中疊加時需要進行一次額外的乘法運算(如上述演算法描述的 2.a), 並且發生溢出的情況下需要重新計算新的調和係數(整數除法運算), 最後在演算法的第三步需要進行一次加法運算(浮點數加法). 因為涉及的數值不會很大, 同時音訊流的資料量較之視頻等要小得很多, 在視訊會議的應用中, 採用調和係數方法進行混音完全在 MCU 承載的能力範圍內, 實測與常規混音演算法比較, 格式為 linear PCM raw, 16 bit, 單聲道, 取樣速率為8000 HZ, 時間30 秒, 幀長30 毫秒的情況下, 其差別不會超過 17ms , 並不會由此產生很大的延遲, 其即時性仍然得到保證, 而從混音的品質來說較常規混音演算法要好很多
arrow
arrow
    全站熱搜

    戮克 發表在 痞客邦 留言(0) 人氣()