计算音频数据音量_【翻译】线性的音量推子……简直像一个个秤砣!
——副標題:給音頻軟件硬件工程師的提示
原文:Programming Volume Controls - dr-lex.be
因為很多程序員缺乏對人類聽覺系統(tǒng)的常識,或者只是因為太懶了,很多音頻軟件都存在一個很煩的問題。當你使用這些音頻軟件的音量控制的時候,會覺得痛不欲生。如果你有機會參與到音頻軟件的開發(fā)中去,那么請仔細閱讀下面這些文本,把它提到的知識燒進自己的腦子里去,甚至跟身邊的人奔走相告!太長不看
- 音量推子是非線性的
線性的音量控制器真的是煩死人了!因為人類對響度的感知是對數(shù)的!這也是為什么所有的音頻設(shè)備都用dB來標示它的音量控制或者增益控制。
對于一個相對的振幅
來說(即 ,其中 是當前值, 是參考值),它對應(yīng)的分貝值是 。正的分貝值表示放大,而負的分貝值表示衰減。將振幅乘以特定的數(shù)值,那么對應(yīng)的分貝值則增加了一定的數(shù)值。
此外,dB(A)經(jīng)常被用來衡量人類感知到的絕對響度。人類平均可以感知到的最小的聲響,被標記為0dB(A),一個“安靜”的房間大概會有±30dB(A)的聲響。
- 一個音量控制器不應(yīng)該是基于百分比的
因為百分比即是線性的。
但是如果這個百分比表示的是dB值的百分比,那就還可以接收。比如0%表示-60dB而100%表示0dB。
- 一個理想的推子應(yīng)該符合指數(shù)曲線
這條曲線的公式為
對于這條曲線來說,它的最小值代表“最安靜”(對消費級產(chǎn)品來說是30dB(A)),而其最大值對應(yīng)了該音頻產(chǎn)品的最大響度。
有個問題是,你在很多情況下只能去猜測用戶使用的是什么產(chǎn)品。所以,除非你是在做一個有明確的標準的高端產(chǎn)品,其實你是可以做一些猜測或者近似的。
一個很好用的估計值是用戶擁有60dB的可調(diào)整范圍。
- 表1給出了一些參數(shù)a和b的經(jīng)驗值
表1中給出了在不同響度范圍下,參數(shù)
和 可設(shè)置的經(jīng)驗值供參考。其中,x是滑塊的位置,其取值范圍為
, 則是作用于波形上的系數(shù),對波形的振幅進行縮放。大概率上,你會使用的是60dB范圍上的參數(shù)。
如果你想要讓推子推到最小的時候,得到完全不輸出信號,那么你可以在接近0的地方給函數(shù)設(shè)置一個線性的滾降(roll-off)。
表1:方程中a和b的值- 不連續(xù)的控制器
如果你的音量控制器是離散的,比如說,用鼠標點擊按鈕、或者鼠標滾輪來控制,那么最好確保每兩“格”音量之間的區(qū)別在1~3dB之間。
小于1dB的音量變化難以被察覺到,而3dB以上的變化則太過于粗糙了。2dB是一個蠻不錯的選擇。
- 近似曲線
如果出于某些原因,你不想做指數(shù)運算,那你可以用一條所需的運算量低得多的冪次曲線來代替。
對于典型的60dB范圍,這是一條4次曲線。換句話說,讓波形振幅乘以系數(shù)
表1中也給出了不同動態(tài)范圍下適用的近似曲線。雖然這些曲線不如對數(shù)曲線那么完美,但是再怎么說都好過你直接塞個線性的音量推子進去!
本文比較長,正文的前半部分都在講關(guān)于分貝的基礎(chǔ)知識。如果你只想看關(guān)于音量推子的部分,可以跳過前半部分,從“尋找理想的曲線”一節(jié)開始閱讀。為什么萬惡的線性的音量控制器是邪惡的
當今的大部分音頻軟件都會帶有控制音量的推子或者旋鈕,其目的是模仿傳統(tǒng)的音頻硬件。不幸的是,大部分的這些軟件控制器上都會有一點讓人屁眼疼。那就是它們是線!性!的!
你也許會問:一個線性的推子犯了什么錯?一端是0,一端是100,中間呈線性增長,不是很棒嗎?答案是不不不不不。
你可以這樣子試試看:打開一個音頻軟件,播一首你喜歡的曲子。把音量旋鈕打到最大,然后稍稍搓動它。接著,把音量調(diào)到最小,然后稍稍搓動它。
如果這時候你聽到,在音量最大的那一端基本沒什么音量變化,而在最小的那一端瘋狂變化。那么這個控制器十有八九就是線性的控制器了![1]
(如果你身邊的播放器都做了正確的事情,你可以看看譯者補充的這個視頻感受下區(qū)別。)
https://www.zhihu.com/video/1227903653497257984這種邪惡甚至已經(jīng)滲透到一些硬件上了!Velleman賣過一款可以拆卸組裝的圖形均衡器K4302,在我1995年買到的版本上,搭載的推子就是線性的,也不知道現(xiàn)在修正了沒有。
甚至iMac G3上的音量控制器也是線性的。
恐怕這些只是眾多使用了線性推子的硬件中的一角。
除了上面提到的,線性的音量控制器還會導致這些癥狀:
- 如果你從最小的音量網(wǎng)上推,只要推一點點就已經(jīng)太大聲了
- 從差不多中間開始,到最大音量,幾乎沒什么變化
- 如果一個高靈敏度的耳機和低輸出的音響接到同一臺電腦上,基本不可能對耳機進行微調(diào)。因為要拖動很大很大的距離,才能讓音響出現(xiàn)音量的改變
種種這些問題,就會讓用戶覺得你的產(chǎn)品難用,但是又找不出為什么,最后只能煩到大罵:
這些音量推子……簡直就像一個個秤砣!
問題出在哪里?
所以線性的音量推子到底怎么了?其實是因為我們對聲音的感知是對數(shù)的。
橫軸:振幅;縱軸:感知響度也就是說,相同的振幅變化,在振幅本身就小的時候,我們感知到的變化程度要比振幅本身比較大的時候更大。
這種特性讓我們能既能聽到振幅很小的聲音,也能聽到振幅超大的聲音?;蛘哒f,我們的聽覺覆蓋了很大的動態(tài)范圍。
而放到音量控制上,線性的推子給出的音量變化,在我們聽來是呈對數(shù)變化的,所以會覺得怪怪的。上圖就是一條對數(shù)曲線。橫軸上標記了兩個完全一樣長度的區(qū)域(也即線性的音量推子)。而縱軸則顯示了聽覺上的音量變化。在音量較小的那段,變化的程度要比較大的那端大。
為了得到一個“真正的”音量推子,我們只需要讓推子的輸出是指數(shù)的。因為
,這樣一來,主觀感知上的音量變化就是線性的了,而這才是我們想要的。在下文中,我假設(shè)音量推子和整個音頻系統(tǒng),都工作在
的值域上。且用 來表示音量推子的位置, 來表示于波形數(shù)據(jù)相乘的系數(shù)。尋找理想的曲線
指數(shù)曲線有兩個很煩的屬性:
- 一是只有自變量是負無窮時,它的值才是0
不過這個問題不大,因為我們的耳朵并沒有擁有無限的敏感度。我們只需要知道一些實用的動態(tài)范圍就行了。這部分在下面再展開講。
- 二是指數(shù)函數(shù)的一般形式 的圖像,即使確定了兩個點之后,還是無法定下具體的三個參數(shù)。
所以在音量控制的場景中,我們省去
這個參數(shù),因為耳朵無法感知到直流偏移(譯者注:感覺這個解釋不是很好,加上 應(yīng)該是整體的音量都提升或衰減,是可以被感知的)。這樣一來,就可以通過兩個點來確定一條具體的曲線了。我們要得到的曲線,一定會經(jīng)過
這個點。于是可以得到剩下的問題就是,確定控制曲線形狀的
值。更小的值生成的曲線更加陡峭,而更大的值生成的曲線則更加平緩。你也許會嘗試把第二個點選擇為
,但是不應(yīng)該是這樣的。就像剛剛說的,指數(shù)函數(shù)在自變量是0的時候可不是0。不過這也不是大問題,因為我們耳朵的對數(shù)響應(yīng)曲線,會在一個非零響度的地方達到0,也即聽閾(The Hearing Threshold)。一般的環(huán)境中,都存在一定的背景噪聲。如果一個聲音的響度低于這個背景噪聲的響度,就可以是不可聞的了。最大的問題是,即使不同人的聽閾大致上是一致的,但是不同的音響系統(tǒng)在相同的輸入信號下,輸出的響度卻和大量的參數(shù)相關(guān)。
為了得到合適的
值,我們需要更多的信息。如果我們想要讓用戶在調(diào)節(jié)音量時的感覺完全是線性的,我們就需要知道一個音頻系統(tǒng)在最大音量時的響度是多少。但是很顯然,這個問題沒有什么實用性。除非你是給特定的硬件系統(tǒng)開發(fā)軟件,否則這個問題很簡單,就是沒有確切的答案。所以我們就需要做一些假設(shè)。這里插一個題外話,就是“響度”是如何被測量的。
聲強的測量
因為人類的聽系統(tǒng)具有對數(shù)的響應(yīng)曲線,人類定義了一個特殊的單位,以Graham Bell的名字命名的“貝爾(Bel)”,來衡量聲音的大小。但是,貝爾的跨度太大了,所以我們經(jīng)常接觸到的單位,是貝爾縮小十倍得到的“分貝”,用dB來表示。1貝爾=10分貝。使用dB作為單位時,可以以絕對標度或者相對標度來計算。
當使用絕對標度時,我們得到的是測量的聲音對于平均人群來說有多大聲,用聲壓級(Sound Pressure Level, SPL)表示。這個標度有幾種不同的變體,最常見的是dB(A)。
要使用dB(A)來度量一個聲音,首先這個聲音要通過一個關(guān)于平均人群的頻率響應(yīng)曲線的濾波器。接著,經(jīng)過一個以10為低的對數(shù)變化,最終再乘以10. 這里不會講到再深入的細節(jié)去了,因為這些在這篇文章里已經(jīng)夠用了。
你應(yīng)該知道的一點是,0dB(A)代表了平均人群能感知到的最小響度,也即聽閾。而在一個安靜的環(huán)境里,通常來說都會有大約30dB(A)的背景噪聲。處在一個0dB(A)的環(huán)境中,其實反而是一種很奇怪的體驗。
人類所能聽到的最大響度,大概是120dB(A)。一支傳統(tǒng)的管弦樂團演奏音樂時的響度大約時94dB(A)。
需要注意的是,由于dB的對數(shù)運算,將一個聲音的功率放大10倍,其實相當于增加了10dB(A).
在幾乎所有的物理度量中,都會使用到相對標度。相對標度可以表達兩個不同的信號或物理量之間的差距。
相對標度的符號就是簡單的dB。其計算方法與你要計算的物理量是振幅還是功率有關(guān)。
對于功率值來說,其公式為
, 代表相對的功率(即兩個功率的比值)對于振幅來說,其公式為 。
產(chǎn)生這種區(qū)別的原因是,功率正比于振幅的平方。在對數(shù)運算中,平方可以提取到對數(shù)運算符的外面,變成系數(shù)2.
理論上來說,絕對標度和相對標度不能真正地互換。當我們對一個90dB(A)的聲音衰減20dB,我們其實無法保證得到的聲音就是精確的70dB。(譯者不太理解這一點)
尋找理想的曲線(第二部分)
在我們學習了這么多關(guān)于分貝的度量的知識之后,我們可以繼續(xù)剛剛尋找兩個參數(shù)的問題了。我們要確保這條曲線能給人們帶來接近線性的主觀感受。
我們先不用考慮低于30dB(A)的部分,因為在大部分環(huán)境里就已經(jīng)有這么大的背景噪聲了。所以我們可以將30dB(A)作為其閾值。
然后我們繼續(xù)假設(shè)用戶的設(shè)備最大可以產(chǎn)生90dB(A)的聲音。這其實已經(jīng)是一個蠻大的音量了,大部分人都不會想要讓自己長時間暴露在大于90dB(A)的環(huán)境中的。也許手機、電腦、平板的內(nèi)置喇叭都達不到這個水平,但是耳機耳塞和Hi-Fi, PA等音箱系統(tǒng)是可以的。
現(xiàn)在我們確定下我們的曲線中的兩個點了,也就是
和 。常用的音量推子控制的都是衰減的值。如果我們把這條曲線放到相對坐標軸里,得到的點就是 和 了。為了讓計算更加直觀,可以給它添加一個60dB的偏移,得到 和 兩個點。從振幅上看,60dB是0dB的 倍。由于
, ,那么a的值就是簡單的 了。現(xiàn)在我們得到的曲線,應(yīng)該具有不錯的實用性,而且在大多數(shù)情況下都能令人滿意了。
理論上講,推子推到最小的位置應(yīng)該對應(yīng)到30dB(A),也就是會被環(huán)境噪聲遮掩掉的水平。盡管沒有必要強制讓這個點的輸出是0,但是實際上我們還是希望它對應(yīng)到0。
因為人們都會期望當音量調(diào)到最小時,聲音設(shè)備不再有輸出,并且我們前面做的估計工作也不可能完全準確。一個最簡單的解決方法就是加一個判斷條件
if(x==0) ampl=0;如果需要更平滑地過渡到0,也可以這樣子:
if(x < 0.1) ampl *= x*10;表1給出了按照前面所講的思路設(shè)計的,不同動態(tài)范圍下理想曲線的
和 的值。(這里的動態(tài)范圍就是最大響度和背景噪聲的差值)你可以在你的代碼里直接使用這個指數(shù)方程。如果你不知道用戶的設(shè)備所能達到的最大響度是多少,就猜一猜吧。上面說到的30到90,就是一個不錯的猜測。
不過這種猜測永遠也不可能準確,因為dB(A)也與播放的聲音的種類有關(guān)。
即使我們算出來的曲線和實際要求有一定的偏差,也比一條愚蠢的線性曲線好不知道多少倍。更別說是用了剛剛說到的平滑的滾降之后的效果了。
尋找不是特別理想但是仍然有不錯的效果的曲線
有些程序員可不想就為了你一個音量腿子,調(diào)用一整個數(shù)學庫!所以,我們可以折衷一下,找到一條接近指數(shù)曲線,但是又不至于那么麻煩的曲線。
下圖繪制出了三條曲線:線性曲線(嫌棄,略略略)、60dB指數(shù)曲線(紅)和
(藍)。就像你的眼睛看到的,藍色的曲線跟紅色的曲線還蠻接近的,而且你還可以看到線性的曲線錯得多么離譜。
四次冪曲線的方程,每次運算只需要做三次乘法(如果你愿意多寫一行代碼,只做兩次乘法也可),而且它經(jīng)過零點。已經(jīng)很優(yōu)秀了吧。
我在一些設(shè)備上嘗試應(yīng)用了4次冪曲線,它給人的感覺十分自然,所以我強烈向你安利它。你也許也會覺得5次冪曲線更好,這取決于你自己了。
如果最大音量沒有那么大,那你可以用一條不那么彎的曲線
,或者如果你的動態(tài)范圍更大,你也可以選擇比 更彎的曲線。比如對于90dB動態(tài)范圍的系統(tǒng)來說, 才是比較好的近似。不過需要用到這么彎的曲線的系統(tǒng)其實不多。表1的最后一列給出了各個動態(tài)范圍下的曲線近似方程。你也可以在下面的圖表里看看這些曲線的近似情況(下方的表格以dB作為縱坐標的單位)。
在推子比較低的位置上,由于冪次曲線降低到0(負無窮分貝)的速度要比指數(shù)曲線快很多,所以這部分的近似比較不理想。放到dB坐標中來看這個差距還是蠻大的。不過看看線性曲線的表現(xiàn),就會覺得這點代價還是可以接受的了。
7次冪曲線在高達120dB動態(tài)范圍的情況下保持了不錯的近似,不過大部分情況下你都不應(yīng)該制造可以發(fā)出100dB(A)聲響的設(shè)備,免得收到因為使用你的設(shè)備而損傷了聽力的訴訟。
后記
人類能夠分辨出的最小的音量區(qū)別,大概是1dB,或者說10%。如果你想要做一個離散的音量控制器,比如通過點擊“+-”符號來調(diào)整音量的控制器,那就最好讓每次點擊調(diào)整都能被感覺到。
但是你也最好不要讓每次點擊的變化太大,如果你的控制器跨度太大了,用戶體驗也不好。
一個比較推薦的經(jīng)驗值每次調(diào)整2dB,且最多不要超過3dB。
在GNOME一個版本的音量調(diào)整中,步長居然達到了5dB。整個網(wǎng)站都在抱怨這個事情。
我有時候會收到別人的郵件,問我應(yīng)該怎么設(shè)置一個被設(shè)計成使用dB作為單位的音量控制器。有人依然覺得它們應(yīng)該對它進行非線性變換。不不不!這種情況下你只需要設(shè)定你需要的范圍和步長就行了!
舉個例子,有些音量控制器給你提供了120dB的動態(tài)范圍,但是如果用不上那么多,你可以把它限制到上半部分的60dB就好了。有些地方可能會同時提供衰減和增益,至于具體怎么用,你就自己多加注意啦!
有些人沒有把這些對數(shù)啦,感知啦理解好,有可能會出現(xiàn)一些奇奇怪怪的想法。
比如說:“一個98dB(A)的聲音太吵了!如果我把它減小到95dB(A),那它就只剩下原來一半的能量,只有一半吵了!”
又對又錯。能量確實是只剩下一半了(振幅衰減至
倍),但是主觀感知只減少了3dB,也就是只比能感受到的變化多那么一點點。因為這就是分貝這個單位本身被提出來的意義呀!在這種情況下,功率對半減少了,對聽力的損傷可沒有減少多少。上面講的這么多,不只是適用于推子,也適用于旋鈕(雖然在軟件里很少見,但是大部分的硬件都用的電位器。這些電位器也都具有指數(shù)的響應(yīng)曲線)和各種情況。甚至在均衡器里也是這樣,即使它們的每個推子都只控制頻譜中的一部分頻率成分。
除了在要求極高的情況下,其實音量控制并不總是十分精確的。總之,這篇文章的中心就是,音量控制器應(yīng)該做成指數(shù)響應(yīng)的,或者,至少讓它的響應(yīng)曲線長得別差太多!
關(guān)于頻率控制和頻率分析
這部分是小得多的問題了,因為大部分應(yīng)用都不需要在用戶端處理頻率。
人類對音高的感知也不是線性的,所以如果你需要對頻率進行操作,也不要用線性的曲線!你必不想聽到一臺按照線性尺度進行調(diào)音的鋼琴!
這不止在聲音合成的領(lǐng)域有關(guān),如果你要做聲音信號分析,也會用到這些知識。如果你想要做一個頻譜分析儀,如果沒有特殊要求,那么它的頻率軸就應(yīng)該是對數(shù)的。如果你把它做成線性的,那么大部分低頻都會被擠壓到小小的一塊空間里,而高頻成分會在一大塊空間里分散開來。
即使我們聽覺的頻率范圍,上限達到了20kHz,但是大概2kHz的位置開始,我們就會覺得音高已經(jīng)很高了。音樂中主要的樂器都集中在2kHz以下。而語音信號中,超過4kHz的成分已經(jīng)不多了(電話就會用一個濾波器濾去這以上的頻率成分)。而這些高頻成分,如果在線性坐標下,會占掉近80%的空間!
不過,要生成一個對數(shù)坐標的頻譜可不容易。FFT是線性的,唯一的辦法就是在做完FFT后,再調(diào)整坐標軸,以對數(shù)的形式去展示數(shù)據(jù)。而這會導致低頻的分辨率低得可憐,而高頻成分又遠超所需的分辨率。為了解決這個問題,你可以在超高的頻率分辨率下來做FFT,使得低頻區(qū)域獲得足夠的分辨率。但是這樣做又會損失掉高頻部分的時間分辨率。也有其他的解決辦法,比如通過一系列濾波器后,對不同頻率的聲音分別采取不同的FFT大小。不過這樣一來,各個頻率成分的時間分辨率又難以統(tǒng)一了。
原文遵守CC BY 4.0協(xié)議
參考
總結(jié)
以上是生活随笔為你收集整理的计算音频数据音量_【翻译】线性的音量推子……简直像一个个秤砣!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql数据丢失_图解MySQL |
- 下一篇: python日期格式修改年月日_Pyth