使用軟件調節音量時如果音量之間的步進太大,聲音突變,就能聽到明顯的爆音,尤其以單音音頻更爲明顯,類似的問題還在聲音起播、暫停、結束、快進快退時經常會出現,這個時候一般需要對音頻進行漸入漸出的效果處理。
先來看一個典型的爆音音頻示例,播放一個1k hz的正玄波,並調節音量,可以看到波形幅度增大
由於幅度跳變太大,過渡不連續,造成爆音,從頻譜圖來看這條豎直的亮線處,就是產生爆音的位置
爲解決這個問題,就需要引入漸入漸出處理了,聲音由大變小時需要做漸出處理,由小變大時需要做漸入處理
所謂漸入漸出處理就是需要一個平滑的過渡,比如從0到1,可以在中間插幾個點,平緩的過渡到1,插多少點和每個點的值帶來的效果也不一樣。這種處理也應用在各種動畫過渡場景中,原理相通。
動畫效果中經常用到的緩動公式,有興趣的同學可以深入研究一下其中的數學原理,有幾個相關的資料網頁:
http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
這個網頁十分強大,可以手動設計緩動效果並生成對應的函數接口
http://blog.moagrius.com/actionscript/jsas-understanding-easing/
這個網頁詳細解釋了函數公式的意義:
These functions are usually written with 4 arguments [2]:
function noEasing (t, b, c, d) {
return c * t / d + b;
}
@t is the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever – as long as the unit is the same as is used for the total time [3].
@b is the beginning value of the property.
@c is the change between the beginning and destination value of the property.
@d is the total time of the tween.
這裏的解釋是針對動畫效果而言,翻譯成音頻來說,我們的音量假設從0增大到1.0
b就代表起始音量0,c表示目標音量到起始音量的差即1.0
d意味着需要對多少樣本做處理,一般我們會以時間來計算,比如我要200ms內的音頻數據緩動處理,那麼這麼樣本總值就是:
d = 200*sr(採樣率)/1000 ,因爲左右聲道是同時處理,我們以frame爲單位,48000採樣率,d的大小爲9600
t就是處理的frame計數了,從0到9600增加,返回值就是當前的frame需要的當前音量,參考代碼如下:
vol_delta = target_volume - current_volume;
for (j = 0; j < nframes; j++) {
if (ease_frames == 0) {
current_volume = target_volume;
} else if (ease_frames_elapsed < ease_frames) {
current_volume= floatEaseNext((float)ease_frames_elapsed,
start_volume, vol_delta, (float)(ease_frames - 1));
ease_frames_elapsed++;
}
for (i = 0 ; i < ch; i++) {
data[j * ch + i] = data[j * ch + i] * current_volume;
}
}
公式有很多種,每種公式處理的過渡效果不一,這是兩種ease in和ease out的處理公式
EaseInCubic:
floatEaseFunc( float t, float b, float c, float d) {
t /= d;
return c * t * t * t + b;
}
EaseOutCubic:
floatEaseFunc( float t, float b, float c, float d) {
t = t / d - 1;
return c * (t * t * t + 1) + b;
}
來看一下實際對音頻突變的處理效果,這是系統在播放1Khz時不斷調整音量時dump的pcm數據
我們從頻譜圖上來看
整段音頻非常乾淨,沒有任何雜音爆破音,處理的相當完美。
據瞭解緩動公式由大神robert penner提出,再次感謝膜拜大神!