本文對(duì)筆者關(guān)于音頻信號(hào)處理中的 Limiter 的理解作以記錄。如有表述不當(dāng)之處歡迎批評(píng)指正。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處。
1. 引言
由于工作上的需要,筆者花了一周左右的時(shí)間對(duì) limiter(它屬于動(dòng)態(tài)范圍控制器里面的一種算法,動(dòng)態(tài)范圍控制器包括 compressor, expander, limiter 和 noise gate 等,感興趣的讀者可參考筆者的另一篇博客)進(jìn)行了研究學(xué)習(xí)。期間也閱讀了不少資料,對(duì) limiter 算是有了較深入地了解。在此對(duì)整個(gè)學(xué)習(xí)過(guò)程、筆者的感悟以及算法背后所蘊(yùn)含的思想作以記錄,以方便后續(xù)回顧和他人學(xué)習(xí)。
相比于音頻信號(hào)處理中的其它算法,limiter 是一個(gè)存在感較低的算法,各種資料上所呈現(xiàn)出的原理和實(shí)現(xiàn)過(guò)程也相對(duì)簡(jiǎn)單,基本一看就懂。但是按照該原理所實(shí)現(xiàn)的 limiter 仍然需要接后處理才能滿足實(shí)際需要。
本文首先介紹了 Matlab 上的實(shí)現(xiàn),筆者稱之為一階遞歸平滑版本的 limiter,該版本也是上面所說(shuō)的大多數(shù)資料上呈現(xiàn)的版本;然后介紹了 FFMPEG 里面的實(shí)現(xiàn),筆者稱之為逐采樣點(diǎn)過(guò)渡平滑的 limiter。兩個(gè)版本各有優(yōu)缺點(diǎn),可根據(jù)具體應(yīng)用的需要選擇相應(yīng)的版本。
2. Limiter 的主要作用
在音頻信號(hào)處理中,通常的做法是先將音頻采樣點(diǎn)歸一化到 [ ? 1.0 , 1.0 ] [-1.0,1.0] [?1.0,1.0],然后再對(duì)其施加各種各樣的音頻算法。然而在算法處理過(guò)程中可能會(huì)出現(xiàn)某些音頻采樣點(diǎn)的幅度超過(guò) 1 1 1 的情況?;蛘咴趯⒍嗦芬纛l流混合成一路音頻流的時(shí)候,采樣點(diǎn)相加的過(guò)程中也有可能出現(xiàn)幅度超過(guò) 1 1 1 的情況。而使用 limiter 的主要目的就是在盡量不變動(dòng)其它采樣點(diǎn)的情況下,將這些采樣點(diǎn)的幅度全部限制在 1 1 1 以內(nèi),以避免削波。
3. 簡(jiǎn)單粗暴做法
考慮下面的采樣點(diǎn)序列
x
(
n
)
,
n
=
1
,
2
,
?
?
,
9
,
10
x(n), n=1,2,\cdots,9,10
x(n),n=1,2,?,9,10:
??
0.990
,
??
0.995
,
??
0.997
,
??
0.999
,
??
1.010
,
??
1.005
,
??
0.998
,
??
0.997
,
??
0.995
,
??
0.992
\; 0.990, \; 0.995, \; 0.997, \; 0.999, \; 1.010, \; 1.005, \; 0.998, \; 0.997, \; 0.995, \; 0.992
0.990,0.995,0.997,0.999,1.010,1.005,0.998,0.997,0.995,0.992
可以看到中間有兩個(gè)采樣點(diǎn)的幅度是超過(guò)
1
1
1 的,而最簡(jiǎn)單粗暴的做法就是令這兩個(gè)采樣點(diǎn)的幅度等于
1
1
1(或者小于
1
1
1 但是又特別特別接近于
1
1
1 的一個(gè)數(shù),這個(gè)數(shù)也稱為 limiter 的閾值,此處令該閾值等于
1
1
1)。經(jīng)過(guò)處理之后,上面的采樣點(diǎn)序列變?yōu)?
x
^
(
n
)
\hat{x}(n)
x^(n):
??
0.990
,
??
0.995
,
??
0.997
,
??
0.999
,
??
1.000
,
??
1.000
,
??
0.998
,
??
0.997
,
??
0.995
,
??
0.992
\; 0.990, \; 0.995, \; 0.997, \; 0.999, \; 1.000, \; 1.000, \; 0.998, \; 0.997, \; 0.995, \; 0.992
0.990,0.995,0.997,0.999,1.000,1.000,0.998,0.997,0.995,0.992
而這種做法可能存在的一個(gè)問(wèn)題就是,相比處理之前,處理之后的采樣點(diǎn)之間出現(xiàn)了突變,變得不平滑,在頻譜上看的話就是高頻多了些東西出來(lái),聽著可能會(huì)有雜音。
4. 簡(jiǎn)單粗暴做法的另一種理解:增益因子
可以換個(gè)角度理解上述簡(jiǎn)單粗暴做法,即
x
^
(
n
)
\hat{x}(n)
x^(n) 是通過(guò)給
x
(
n
)
x(n)
x(n) 中的每個(gè)采樣點(diǎn)乘以相應(yīng)的增益因子得到的,而這個(gè)增益因子序列
g
(
n
)
g(n)
g(n) 為:
1
,
??
1
,
??
1
,
??
1
,
??
1
/
1.010
,
??
1
/
1.005
,
??
1
,
??
1
,
??
1
,
??
1
,
1, \; 1, \; 1, \; 1, \; 1/1.010, \; 1/1.005, \; 1, \; 1, \; 1, \; 1,
1,1,1,1,1/1.010,1/1.005,1,1,1,1,
也就是說(shuō)
x
^
(
n
)
=
x
(
n
)
g
(
n
)
\hat{x}(n) = x(n) g(n)
x^(n)=x(n)g(n)??梢钥吹?,幅度小于 limiter 閾值的采樣點(diǎn)的增益因子為
1
1
1。幅度大于 limiter 閾值的采樣點(diǎn)的增益因子小于
1
1
1,且幅度越大,增益因子越小。也就是說(shuō),增益因子可由以下公式計(jì)算:
g
(
n
)
=
{
1
,
abs
(
x
(
n
)
)
≤
l
t
l
t
/
abs
(
x
(
n
)
)
,
abs
(
x
(
n
)
)
>
l
t
(1-1)
g(n) = \begin{cases} 1, & \text{abs}(x(n)) \leq lt \\ lt / \text{abs}(x(n)), & \text{abs}(x(n)) > lt \end{cases} \tag{1-1}
g(n)={1,lt/abs(x(n)),?abs(x(n))≤ltabs(x(n))>lt?(1-1)
其中 l t lt lt 表示 limiter 的閾值(此處取值為 1 1 1)。上一節(jié)提到這種簡(jiǎn)單粗暴做法可能會(huì)導(dǎo)致采樣點(diǎn)之間出現(xiàn)突變,引入增益因子這個(gè)概念之后,這種突變就可以理解為增益因子之間的突變。因此,為了解決這種突變,目前大多數(shù)做法都是對(duì)增益因子 g ( n ) g(n) g(n) 做平滑。接下來(lái)介紹的兩個(gè)版本都是用的這個(gè)思想,區(qū)別在于所使用的平滑方法。
5. 一階遞歸平滑版本的 Limiter
這兒參考 Matlab 中的實(shí)現(xiàn)來(lái)進(jìn)行說(shuō)明,其它資料中的實(shí)現(xiàn)也大差不差,基本一致(也可參考 DAFX: Digital Audio Effects Second Edition 中的實(shí)現(xiàn))。這類實(shí)現(xiàn)使用一階遞歸平滑的方法對(duì)增益因子進(jìn)行平滑,這也是音頻信號(hào)處理中常用的平滑方法。平滑的增益因子
g
s
(
n
)
g_s(n)
gs?(n) 可以通過(guò)以下式子計(jì)算得到:
g
s
(
n
)
=
{
(
1
?
α
a
)
?
g
s
(
n
?
1
)
+
α
a
?
g
(
n
)
,
g
(
n
)
<
=
g
s
(
n
?
1
)
(
1
?
α
r
)
?
g
s
(
n
?
1
)
+
α
r
?
g
(
n
)
,
g
(
n
)
>
g
s
(
n
?
1
)
(1-2)
g_s(n) = \begin{cases} (1-\alpha_{a}) \, g_s(n-1) + \alpha_{a} \, g(n), & g(n) <= g_s(n-1) \\ (1-\alpha_{r}) \, g_s(n-1) + \alpha_{r} \, g(n), & g(n) > g_s(n-1) \end{cases} \tag{1-2}
gs?(n)={(1?αa?)gs?(n?1)+αa?g(n),(1?αr?)gs?(n?1)+αr?g(n),?g(n)<=gs?(n?1)g(n)>gs?(n?1)?(1-2)
其中
α
a
\alpha_{a}
αa? 是所謂的攻擊時(shí)間(attack time)系數(shù),
α
r
\alpha_{r}
αr? 是釋放時(shí)間(release time)系數(shù),可以通過(guò)下式計(jì)算:
α
?
=
1
?
exp
(
?
log
e
(
9
)
F
s
×
T
?
)
\begin{align} \alpha_{*} = 1 - \text{exp}(\frac{-\text{log}_{\text{e}}(9)}{F_s \times T_{*}}) \tag{1-3} \end{align}
α??=1?exp(Fs?×T???loge?(9)?)?(1-3)?
用具體的攻擊時(shí)間或釋放時(shí)間替換 T ? T_{*} T?? (單位為秒)即可得到對(duì)應(yīng)的攻擊時(shí)間系數(shù)或釋放時(shí)間系數(shù)。 F s F_{s} Fs? 是音頻信號(hào)的采樣率??梢钥吹狡交蟮脑鲆嬉蜃? g s ( n ) g_s(n) gs?(n) 是對(duì)當(dāng)前采樣點(diǎn)的增益因子 g ( n ) g(n) g(n) 和歷史采樣點(diǎn)的增益因子 g ( n ? 1 ) , ? g ( n ? 2 ) , ? g ( n ? 3 ) ? g ( 1 ) g(n-1), \, g(n-2), \, g(n-3) \cdots g(1) g(n?1),g(n?2),g(n?3)?g(1) 做了指數(shù)平滑。
將上述平滑之后的增益因子與原始信號(hào)相乘,就可得到一階遞歸平滑版本的 limiter 的處理結(jié)果: x ^ s ( n ) = x ( n ) g s ( n ) \hat{x}_{s}(n) = x(n)g_s(n) x^s?(n)=x(n)gs?(n)。
5.1 攻擊時(shí)間和釋放時(shí)間
關(guān)于攻擊時(shí)間和釋放時(shí)間的介紹可以參考 Matlab。下面筆者舉例說(shuō)明下對(duì)這兩個(gè)時(shí)間的理解,后續(xù) FFMPEG 實(shí)現(xiàn)的 limiter 也用到了這兩個(gè)參數(shù)。
考慮一個(gè)正在參加短跑體測(cè)的大學(xué)生,他需要從 0 m/s 0\text{m/s} 0m/s 快速加速到他的最大速度 8 m/s 8\text{m/s} 8m/s,等跑到終點(diǎn)后再慢慢減速到 0 m/s 0\text{m/s} 0m/s。其中加速所用的時(shí)間在這里相當(dāng)于攻擊時(shí)間,減速所用的時(shí)間相當(dāng)于釋放時(shí)間。更一般的來(lái)說(shuō),攻擊時(shí)間可以理解為從初始狀態(tài)切換到期望狀態(tài)所用的時(shí)間,釋放時(shí)間可以理解為從期望狀態(tài)恢復(fù)到初始狀態(tài)所用的時(shí)間。在這里大學(xué)生的初始狀態(tài)就是 0 m/s 0\text{m/s} 0m/s,期望狀態(tài)就是 8 m/s 8\text{m/s} 8m/s。大部分情況下攻擊時(shí)間短于釋放時(shí)間。
再按照此方式解釋下 limiter 中的攻擊時(shí)間和釋放時(shí)間。假設(shè) F s = 44100 F_s = 44100 Fs?=44100, T a = 0.001 s T_{a} = 0.001s Ta?=0.001s, T r = 0.005 s T_{r} = 0.005s Tr?=0.005s(即 α a = 0.0486 , α r = 0.0099 \alpha_{a} = 0.0486, \alpha_{r} = 0.0099 αa?=0.0486,αr?=0.0099)。將 g ( n ) g(n) g(n) 的值代入上述平滑公式可得 g s ( n ) = g ( n ) = 1 , n = 1 , 2 , 3 , 4 g_s(n) = g(n) = 1, n = 1,2,3,4 gs?(n)=g(n)=1,n=1,2,3,4。該取值是增益因子的初始狀態(tài),而 g ( 5 ) = 1 / 1.010 = 0.990 g(5) = 1/1.010 = 0.990 g(5)=1/1.010=0.990 這是增益因子的期望狀態(tài)。那么增益因子從初始狀態(tài) 1 1 1 切換到期望狀態(tài) 0.990 0.990 0.990 需要多長(zhǎng)時(shí)間哪?這就是由攻擊時(shí)間決定的。使用一階遞歸平滑方法的話, g ( 5 ) g(5) g(5) 的值需要持續(xù) T a = 0.001 T_{a} = 0.001 Ta?=0.001 秒之多,在這么多的值上遞歸平滑之后, g s g_s gs? 的值才會(huì)逐漸接近 0.990 0.990 0.990。不過(guò)可以看到 g ( 5 ) g(5) g(5) 的值只持續(xù)了一個(gè)采樣點(diǎn),而且 g ( n ) > g ( 5 ) , n = 6 , 7 , 8 , 9 , 10 g(n) > g(5), n=6,7,8,9,10 g(n)>g(5),n=6,7,8,9,10,因此 g s g_s gs? 的值將不會(huì)接近 0.990 0.990 0.990。釋放時(shí)間也可以這么理解,即讓增益因子從小于 1 1 1(期望狀態(tài)) 恢復(fù)到等于 1 1 1(初始狀態(tài)),需要增益因子為 1 1 1 的采樣點(diǎn)持續(xù) T r = 0.005 T_{r} = 0.005 Tr?=0.005 秒之多??梢钥吹揭浑A遞歸平滑方法存在滯后性,需要相應(yīng)的采樣點(diǎn)持續(xù)一段時(shí)間之后, g s g_s gs? 的取值才能接近所要的增益因子取值。
上面只是解釋了 limiter 中攻擊時(shí)間和釋放時(shí)間的含義與作用,如果讀者想進(jìn)一步了解為什么攻擊時(shí)間和攻擊時(shí)間系數(shù)(或釋放時(shí)間和釋放時(shí)間系數(shù))是上面那樣的公式關(guān)系,又或者為什么攻擊時(shí)間系數(shù)(或釋放時(shí)間系數(shù))是以上面那樣的方式參與到一階遞歸平滑公式中的,可以查閱更多的資料學(xué)習(xí)研究。
5.2 存在的問(wèn)題
按照上述方法計(jì)算出的 x ^ s ( 5 ) \hat{x}_{s}(5) x^s?(5) 和 x ^ s ( 6 ) \hat{x}_{s}(6) x^s?(6) 的幅度依然是大于 1 1 1 的(感興趣的讀者可以按照上述公式計(jì)算下),只不過(guò)比原始的 x ( 5 ) x(5) x(5) 和 x ( 6 ) x(6) x(6) 的幅度小了。但并沒有從根本上解決將幅度限制在 1 1 1 以內(nèi)的這個(gè)問(wèn)題。
DAFX: Digital Audio Effects Second Edition 中有提到為了較好地解決這個(gè)問(wèn)題,可以后接一個(gè) soft clipping。
筆者還想到另一個(gè)處理該問(wèn)題的方法,但并不能保證 100% 解決。方法就是將 limiter 的閾值降低,也就是說(shuō)不要用 1 1 1 或小于 1 1 1 但又特別特別接近于 1 1 1 的數(shù)來(lái)當(dāng)閾值,而是用一個(gè)較小的閾值,比如 0.9 0.9 0.9。
不過(guò),經(jīng)過(guò)上面的分析可以看到,這個(gè)版本的 limiter 可以做到零延遲,某些對(duì)延遲要求較高的應(yīng)用,可以使用它。
6 逐采樣點(diǎn)過(guò)渡平滑版本的 Limiter
這兒講的是 FFMPEG 中的實(shí)現(xiàn),是筆者在偶然間發(fā)現(xiàn)的,但又不知該怎么稱呼好,因此叫了這個(gè)名字。與上述版本相比,該版本的 limiter 使用不同的平滑方法。上面提到,一階遞歸平滑版本存在增益因子滯后性的問(wèn)題,從而導(dǎo)致處理完的采樣點(diǎn)的幅度可能大于閾值,但它可以做到零延遲。而該版本可以做到增益因子零滯后,也就是能保證處理完的采樣點(diǎn)的幅度不大于閾值,但它卻做不到零延遲。也就是說(shuō)該版本要計(jì)算當(dāng)前采樣點(diǎn)最終的增益因子,必須要用到未來(lái)采樣點(diǎn)的信息。
考慮一個(gè)簡(jiǎn)單的采樣點(diǎn)序列
x
1
(
n
)
,
n
=
1
,
2
,
?
?
,
9
,
10
x_{1}(n), n=1,2,\cdots,9,10
x1?(n),n=1,2,?,9,10:
0.990
,
??
0.995
,
??
0.997
,
??
0.999
,
??
1.010
,
??
0.999
,
??
0.998
,
??
0.997
,
??
0.995
,
??
0.992
0.990, \; 0.995, \; 0.997, \; 0.999, \; 1.010, \; 0.999, \; 0.998, \; 0.997, \; 0.995, \; 0.992
0.990,0.995,0.997,0.999,1.010,0.999,0.998,0.997,0.995,0.992
當(dāng)閾值
l
t
=
1
lt=1
lt=1 時(shí),該序列所對(duì)應(yīng)的增益因子
g
1
(
n
)
g_{1}(n)
g1?(n) 為:
1
,
??
1
,
??
1
,
??
1
,
??
1
/
1.010
,
??
1
,
??
1
,
??
1
,
??
1
,
??
1
1, \; 1, \; 1, \; 1, \; 1/1.010, \; 1, \; 1, \; 1, \; 1, \; 1
1,1,1,1,1/1.010,1,1,1,1,1
可以看到除了
g
1
(
5
)
=
1
/
1.010
=
0.990
g_{1}(5) = 1/1.010 = 0.990
g1?(5)=1/1.010=0.990 之外,其余增益因子均等于
1
1
1。FFMPEG 中的做法就是讓增益因子從
1
1
1 均勻地過(guò)渡到
0.990
0.990
0.990, 然后再?gòu)?
0.990
0.990
0.990 均勻地過(guò)渡到
1
1
1。具體做法如下:
在攻擊階段,讓增益因子從
g
1
(
2
)
g_{1}(2)
g1?(2) 開始逐漸平滑過(guò)渡到
g
1
(
5
)
=
0.990
g_{1}(5) = 0.990
g1?(5)=0.990,一個(gè)可取的做法就是從
g
1
(
2
)
g_{1}(2)
g1?(2) 開始,每個(gè)增益因子在前一個(gè)增益因子的基礎(chǔ)上加
(
0.990
?
1
)
/
(
5
?
2
+
1
)
=
?
0.0025
(0.990-1)/(5-2+1)=-0.0025
(0.990?1)/(5?2+1)=?0.0025。經(jīng)過(guò)運(yùn)算后,前五個(gè)增益因子的取值分別為
1
,
??
0.9975
,
??
0.995
,
??
0.9925
,
??
0.990
1, \; 0.9975, \; 0.995, \; 0.9925, \; 0.990
1,0.9975,0.995,0.9925,0.990 達(dá)到了逐漸平滑到
g
1
(
5
)
=
0.990
g_{1}(5) = 0.990
g1?(5)=0.990 的目的,且不存在滯后性。同理,在釋放階段,可以讓增益因子從
g
1
(
5
)
=
0.990
g_{1}(5)=0.990
g1?(5)=0.990 逐漸平滑過(guò)渡到
g
1
(
10
)
=
1
g_{1}(10)=1
g1?(10)=1。即從
g
1
(
6
)
g_{1}(6)
g1?(6) 開始,每個(gè)增益因子在前一個(gè)增益因子的基礎(chǔ)上加
(
1
?
0.990
)
/
(
10
?
6
+
1
)
=
0.002
(1-0.990)/(10-6+1)=0.002
(1?0.990)/(10?6+1)=0.002。經(jīng)過(guò)運(yùn)算后,后五個(gè)增益因子的取值分別為
0.992
,
??
0.994
,
??
0.996
,
??
0.998
,
??
1
0.992, \; 0.994, \; 0.996, \; 0.998, \; 1
0.992,0.994,0.996,0.998,1。該版本最終平滑過(guò)后的增益因子
g
1
s
(
n
)
g_{1s}(n)
g1s?(n) 為:
1
,
??
0.9975
,
??
0.995
,
??
0.9925
,
??
0.990
,
??
0.992
,
??
0.994
,
??
0.996
,
??
0.998
,
??
1
1, \; 0.9975, \; 0.995, \; 0.9925, \; 0.990, \; 0.992, \; 0.994, \; 0.996, \; 0.998, \; 1
1,0.9975,0.995,0.9925,0.990,0.992,0.994,0.996,0.998,1
最后,再將 x 1 ( n ) x_{1}(n) x1?(n) 與 g 1 s ( n ) g_{1s}(n) g1s?(n) 相乘,就得到了 FFMPEG 版的結(jié)果??梢钥吹剑?jīng)過(guò)處理之后,采樣點(diǎn)的幅度都不大于閾值。
上面就是 FFMPEG 中 limiter 的實(shí)現(xiàn)原理。相信讀者看完之后應(yīng)該能理解筆者為什么起這個(gè)名字稱呼它了。讀者可以算算上述例子中的攻擊時(shí)間和釋放時(shí)間分別是多少,攻擊時(shí)間和釋放時(shí)間越大,最終計(jì)算的增益因子之間的差異就越小,增益因子之間就越平滑。還需要注意到的是 g 1 s ( 2 ) g_{1s}(2) g1s?(2) 的值與 g 1 ( 5 ) g_{1}(5) g1?(5) 的值有關(guān),因此該方法無(wú)法做到零延遲,而且延遲時(shí)間等于攻擊時(shí)間。
上面只是簡(jiǎn)單說(shuō)明了該版本的思想,看著也挺簡(jiǎn)單,沒什么難度,但實(shí)際情況往往更加復(fù)雜。比如一段音頻序列中短時(shí)間內(nèi)出現(xiàn)多個(gè)幅度超出閾值的采樣點(diǎn),應(yīng)該怎么處理才能保證讓每個(gè)采樣點(diǎn)都能滿足要求那。這才是該版本的難點(diǎn)之一,筆者能力有限,不能用簡(jiǎn)潔的語(yǔ)言描述清楚這個(gè)過(guò)程。感興趣的讀者可以閱讀 FFMPEG 的實(shí)現(xiàn),了解了其思想之后,看起來(lái)就能容易些。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-833750.html
7 總結(jié)
在初步接到這個(gè)需求的時(shí)候,是想實(shí)現(xiàn)一個(gè)延遲可設(shè)的 limiter, 本以為不會(huì)花太多的時(shí)間和精力,應(yīng)該很快就能完成。但隨著深入學(xué)習(xí)研究,才發(fā)現(xiàn)一個(gè)小小的算法,要想一步一步優(yōu)化它,讓它更加完美,也并不是像它表面看起來(lái)那么簡(jiǎn)單。從發(fā)現(xiàn)問(wèn)題到提出解決方案,這后面蘊(yùn)含的思想是十分美妙的,這也是算法的魅力之一。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-833750.html
到了這里,關(guān)于聊聊音頻信號(hào)處理中一個(gè)不太起眼的算法-limiter的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!