­

多媒體開發(5)&音頻特徵:聲音可以調大一點嗎?

基本上,現在常用的聲音取樣辦法是pcm,而對於壓縮音頻的解碼,得到的也pcm數據。這個pcm數據,只是一堆數值,有正有負,看這個值看不出什麼花樣。

聲音採集,採的是什麼呢?

採的是聲音的強度變化,也是聲音這種能量的強弱變化,這種強弱用分貝來表示,即dB。所以,pcm數據跟這個dB就一定有關係,這個關係是這樣的:
dB=20∗log10(pcm)
pcm=pow(10,(dB/20.0))

模數轉換ADC時常用的位深是16bit,也就是用16位來表示一個sample,這裡不考慮偷懶而使用不足16位的情況。16位能表示65536個值,也就意味著有65536個dB可以表示出來,哪又怎麼樣?很厲害了嗎?

的確是比較厲害的了。

16位的pcm數值,分正負,那正數的範圍是0至32767,負數的範圍是-1至-32768,隨便挑幾個來看看,對應的dB是多少,如下圖:
pcm對應的dB

由上面的運算可知,16位的pcm值,如果不分正負,最大可以表示96dB,如果分正負,也能表示到90dB。90dB是什麼概念?有數據表明(我也不清楚什麼數據),85dB就會傷害了你,90dB相當於摩托車啟動的聲音–你有開過嗎?

所以,你的pcm數據需要去到90dB以上嗎?想禍害誰?一般情況下,能表示到90dB就很夠用了。

既然知道了pcm數值與dB的關係,就可以搞點事情了,比如把pcm轉成dB後再放大一點,再保存成新的文件,是不是播放就可以大聲一點了呢?

來做個實驗。

import math
import math
import wave
import audioread
import contextlib
import sys
import math
import struct

def gainpcm(filepath):
    try:
        with audioread.audio_open(filepath) as f:
            with contextlib.closing(wave.open(filepath+'.wav', 'w')) as of:
                of.setnchannels(f.channels)
                of.setframerate(f.samplerate)
                of.setsampwidth(2)
                for buf in f:
                    for i in range(0, len(buf)-2, 2):
                        s = buf[i] + buf[i+1]
                        pcm = struct.unpack('<h', s)[0]
                        apcm = abs(pcm)
                        if apcm==0:
                            apcm=1
                        db = 20*math.log10(apcm)
                        db = db * 1.2
                        apcm=int(math.pow(10, float(db)/20.0))
                        if apcm>32767:
                            apcm=32767
                        if pcm < 0:
                            pcm=-apcm
                        else:
                            pcm = apcm
                        tbuf = struct.pack('<h', pcm)
                        of.writeframes(tbuf)

    except audioread.DecodeError:
        print("File could not be decoded.")
        sys.exit(1)

if __name__ == '__main__':
    gainpcm('test.mp3')

這裡是對程式碼的簡單解釋:
程式碼解釋

把一個mp3放過去試驗,出來一個wav,發現wav文件的聲音真的大了好多(好多是因為這裡設置了db*1.2)。但是,另一個問題也暴露出來了,就是聽起來聲音失真很嚴重了,這是因為放大到這個程度,很多apcm都超過了32767,也就是人們說的截頂失真了,看一下原文件與放大後的文件波形圖就更清楚了:
原文件波形

改變db文件波形

由於不能上傳音頻,這裡就不提供直接的音頻對比了。

由此可見,要想不失真,那db就不要乘那麼大的數啊–另一個辦法:給它限幅(壓幅),或者直接使用更合適的整體技術(靈活變音量跟限幅都考慮進去了)比如agc或drc等,明顯這個不是這裡的內容。

好了,總結一下,本文演示了改變音量的一種最原始的辦法,就是直接改pcm的值(轉dB再改變,其實也可以直接改變pcm值),但這不是最好的辦法,因為它會引入失真的副作用。而從pcm數據中提取出能量(dB),這個也更像是音頻特徵的技能。有緣再見,see you。

Tags: