如何利用python處理原始音頻數(shù)據(jù)
一、基礎(chǔ)知識
PCM(pulse code modulation)
,即脈沖編碼調(diào)制,是將模擬信號轉(zhuǎn)為數(shù)字信號的一種編碼系統(tǒng)。而模數(shù)轉(zhuǎn)換主要分兩步,首先對連續(xù)的模擬信號進行采樣,然后把采樣得到的數(shù)據(jù)轉(zhuǎn)化為數(shù)值,即量化。
設(shè)x xx為輸入信號,F(xiàn) ( x ) F(x)F(x)為量化后的信號,則F ( x ) F(x)F(x)既可以是線性的,也可以是非線性的。在audioop
中,主要提供三種編碼支持,分別是a-Law
,μ-Law
以及ADPCM
。
在中國和歐洲主要實用的編碼方式為A-Law,其表達式為:
其中A AA為壓縮系數(shù),在G.726標(biāo)準(zhǔn)中建議87.56。
ADPCM(Adaptive Differential PCM)
,即自適應(yīng)差分PCM。
由于模擬信號的連續(xù)性,一般來說相鄰時間單位的信號往往具有較高的線性度,甚至彼此相差無幾,從而可以被高效率的壓縮。然而,也存在跳躍幅度較大的信號,如果完全以緩變?yōu)樵瓌t,那么必然會丟失這部分數(shù)據(jù)。為了均衡這種差異,就需要進行自適應(yīng)量化。
audioop中支持的Intel/DVI ADPCM算法可以在網(wǎng)上找到,但是信息并不多而且都很老舊,貌似不太重要的樣子,甚至知網(wǎng)都搜不到,所以這里就不詳細解讀了。
二、轉(zhuǎn)換函數(shù)
audioop
提供了ADPCM
、A-Law
和μ-Law
和線性采樣之間的轉(zhuǎn)換函數(shù)
采樣 | ADPCM | A-Law | μ-Law |
---|---|---|---|
lin2lin | lin2adpcm | lin2alaw | lin2ulaw |
adpcm2lin | alaw2lin | ulaw2lin |
其中,與A-Law
和μ-Law
有關(guān)的轉(zhuǎn)換函數(shù)的輸入?yún)?shù)為(fragment
, width
),分別代表待處理片段和位寬;adpcm
則會多一個state
元組作為第三個參數(shù),表示編碼器狀態(tài)。
lin2lin
是將線性片段在1、2、3 和 4 字節(jié)格式之間轉(zhuǎn)換的函數(shù),其輸入?yún)?shù)為(fragment
, width
, newwidth
)。
下面新建一些數(shù)據(jù)來測試一下編碼轉(zhuǎn)換函數(shù),
#下面代碼來自于test_audioop.py import audioop import sys import unittest pack = lambda width, data :b''.join( ? ? v.to_bytes(width, sys.byteorder, signed=True) for v in data) packs = {w: (lambda *data, width=w: pack(width, data)) for w in (1, 2, 3, 4)} unpack = lambda width, data: [int.from_bytes( ? ? data[i: i + width], sys.byteorder, signed=True) ? ? for i in range(0, len(data), width)] datas = { ? ? 1: b'\x00\x12\x45\xbb\x7f\x80\xff', ? ? 2: packs[2](0, 0x1234, 0x4567, -0x4567, 0x7fff, -0x8000, -1), ? ? 3: packs[3](0, 0x123456, 0x456789, -0x456789, 0x7fffff, -0x800000, -1), ? ? 4: packs[4](0, 0x12345678, 0x456789ab, -0x456789ab, ? ? ? ? ? ? ? ? 0x7fffffff, -0x80000000, -1), }
則datas的值為:
>>> for key in datas : print(datas[key])
...
b'\x00\x12E\xbb\x7f\x80\xff'
b'\x00\x004\x12gE\x99\xba\xff\x7f\x00\x80\xff\xff'
b'\x00\x00\x00V4\x12\x89gEw\x98\xba\xff\xff\x7f\x00\x00\x80\xff\xff\xff'
b'\x00\x00\x00\x00xV4\x12\xab\x89gEUv\x98\xba\xff\xff\xff\x7f\x00\x00\x00\x80\xff\xff\xff\xff'
>
則其轉(zhuǎn)換函數(shù)測試如下:
>>> datas[1]
b'\x00\x12E\xbb\x7f\x80\xff' #將要處理的1位線性碼
>>> unpack(1,datas[1])
[0, 18, 69, -69, 127, -128, -1]#轉(zhuǎn)為整型
# 將1字節(jié)線性碼轉(zhuǎn)為2字節(jié)線性碼
>>> datas1_2 = audioop.lin2lin(datas[1], 1, 2)
>>> print(datas1_2)
b'\x00\x00\x00\x12\x00E\x00\xbb\x00\x7f\x00\x80\x00\xff'
>>> unpack(2,datas1_2) #轉(zhuǎn)為整型,其值為datas[1]*256
[0, 4608, 17664, -17664, 32512, -32768, -256]
# 將1字節(jié)線性碼轉(zhuǎn)為1字節(jié)u-Law碼
>>> datas1_u = audioop.lin2ulaw(datas[1], 1)
>>> unpack(1,datas1_u) #轉(zhuǎn)為整型,這個數(shù)和u-law的公式對不上,可能是其他算法
[-1, -83, -114, 14, -128, 0, 103]
三、片段特征函數(shù)
下表中函數(shù)的輸入為(fragment
, width
),分別代表待統(tǒng)計片段和位寬。
返回值 | |
---|---|
avg | 片段采樣值的均值 |
avgpp | 片段采樣值的平均峰峰值 |
max | 片段采樣值的最大絕對值 |
maxpp | 聲音片段中的最大峰峰值 |
minmax | 由片段采樣值中最小和最大值組成的元組 |
rms | 片段的均方根 |
cross | 片段穿越零點的次數(shù) |
getsample(fragment, width, index)
,顧名思義用于采樣,返回段中采樣值索引index的值。
findfactor(fragment, reference)
,返回一個系數(shù)F使得rms(add(fragment, mul(reference, -F)))
最小,即返回的系數(shù)乘以reference
后與fragment
最匹配。兩個片段都應(yīng)包含 2 字節(jié)寬的采樣。
findfit(fragment, reference)
,盡可能嘗試讓 reference
匹配 fragment
的一部分。
findmax(fragment, length)
,在fragment
中搜索所有長度為length的采樣切片中,能量最大的那一個切片,即返回 i 使得 rms(fragment[i*2:(i+length)*2]) 最大。
四、片段操作
其返回值均為片段,下表的參數(shù)中,f表示fragment,w表示width,L表示lfactor,R表示rfactor
audioop.ratecv(f, w, nchannels, inrate, outrate, state[, weightA[, weightB]])
可用于轉(zhuǎn)換輸入片段的幀速率,其中
- state為元組,表示轉(zhuǎn)換器狀態(tài)
- weightA和weightB是簡單數(shù)字濾波器的參數(shù),默認為 1 和 0。
到此這篇關(guān)于如何利用python處理原始音頻數(shù)據(jù)的文章就介紹到這了,更多相關(guān)利用python處理原始音頻數(shù)據(jù)內(nèi)容請搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。