1. 程式人生 > >WAV格式文件合並&幀頭數據體解析(python)(原創)

WAV格式文件合並&幀頭數據體解析(python)(原創)

fmt font 結果 spl ike data- 分享圖片 aid str

一,百度百科

  WAV為微軟公司(Microsoft)開發的一種聲音文件格式,它符合RIFF(Resource Interchange File Format)文件規範,用於保存Windows平臺的音頻信息資源,被Windows平臺及其應用程序所廣泛支持,該格式也支持MSADPCM,CCITT A LAW等多種壓縮運算法,支持多種音頻數字,取樣頻率和聲道,標準格式化的WAV文件和CD格式一樣,也是44.1K的取樣頻率,16位量化數字,因此在聲音文件質量和CD相差無幾! WAV打開工具是WINDOWS的媒體播放器。

  通常使用三個參數來表示聲音,量化位數,取樣頻率和采樣點振幅。量化位數分為8位,16位,24位三種,聲道有單聲道和立體聲之分,單聲道振幅數據為n*1矩陣點,立體聲為n*2矩陣點,取樣頻率一般有11025Hz(11kHz) ,22050Hz(22kHz)和44100Hz(44kHz) 三種,不過盡管音質出色,但在壓縮後的文件體積過大!相對其他音頻格式而言是一個缺點,其文件大小的計算方式為:WAV格式文件所占容量(B) = (取樣頻率 X量化位數X 聲道) X 時間 / 8 (字節= 8bit) 每一分鐘WAV格式的音頻文件的大小為10MB,其大小不隨音量大小及清晰度的變化而變化。

  WAV是最接近無損的音樂格式,所以文件大小相對也比較大。 二,文件幀頭

技術分享圖片

圖1 WAV文件幀頭data[0:44]數據格式

技術分享圖片

圖2.WAV文件幀頭圖解

讀取WAV文件程序:

 1 import struct
 2 
 3 with open(測試音頻源1.wav, rb) as file:
 4     data=file.read()
 5     # print(len(data))
 6     # print(data[44:])
 7     # print(data[0:4])            # chunkID:          b‘RIFF‘
8 # length0=struct.unpack(‘<L‘, bytes(data[4:8])) 9 # print(length0) # (140836,) 10 # print(data[4:8]) # chunkSize: b‘$&\x02\x00‘ WAV文件總byte數 11 # print(data[8:12]) # format: b‘WAVE‘ 12 # print(data[12:16]) # Subchunk1 ID: b‘fmt ‘
13 # length1=struct.unpack(‘<L‘, bytes(data[16:20])) 14 # print(length1) # (16,) 15 # print(data[16:20]) # format Code: b‘\x10\x00\x00\x00‘ 16 # 17 # print(data[20:22]) # Subchunk1 Size: b‘\x01\x00‘ 18 # print(data[22:24]) # nChannels: b‘\x01\x00‘ 19 # 20 # print(data[24:28]) # nSamplesPerSec: b‘\x80>\x00\x00‘ 21 # print(data[28:32]) # nAvgBytesPerSec: b‘\x00}\x00\x00‘ 22 # 23 # print(data[32:34]) # nBlockAlign: b‘\x02\x00‘ 24 # print(data[34:36]) # wBitsPerSample: b‘\x10\x00‘ 25 # 26 # print(data[36:40]) # Subchunk2 ID: b‘data‘ 27 # length2=struct.unpack(‘<L‘, bytes(data[40:44])) # (140800,) 28 # print(length2) 29 # print(data[40:44]) # Subchunk2 Size: b‘\x00&\x02\x00‘

通過將data值輸出,可知其是一個byte文件

幀頭數據為data[0:44],例如:

其中又劃分出3大子塊,每個子塊又分為若幹功能塊。有標誌位、數據長度、通道數、采樣率等等相關參數。

1 bRIFF\xac\xdc9\x00WAVEfmt\x10\x00\x00\x00\x01\x00\x01\x00\x80>\x00\x00\x00}\x00\x00\x02\x00\x10\x00data\x80\xdc9\x00

數據幀為data[44:],剩余的數據即為音頻采樣數據。

三,WAV文件無損合並

我這種方法只針對通道數、采樣率等等(除了文件數據幀長度不同)都相同的多個WAV文件合並,當然如果想要將不同格式的WAV合並也可以先轉換成相同格式的文件之後再做操作。

 1 import struct   # 用於將chunkSize和Subchunk2 Size進行【long int】(byte型)和 int的轉換
 2 
 3 # *** 讀取WAV音頻1 *** #
 4 with open(測試音頻源1.wav, rb) as file:
 5     data1=file.read()
 6 
 7 # *** 讀取WAV音頻2 *** #
 8 with open(測試音頻源2.wav, rb) as file:
 9     data2=file.read()
10 
11 data_info = data1[:44]  # 復制幀頭參考
12 data_out = data1[44:] + data2[44:]  # 將兩個音頻的數據幀合並(都是相同格式)
13 data_info = data_info[:4] + struct.pack(<L, len(data_out)+44) + data_info[8:]# 更新WAV文件的總byte數(兩個文件數據幀和+44)
14 data_info = data_info[:40] + struct.pack(<L, len(data_out)) + data_info[44:]# 更新WAV文件的數據byte數(兩個文件數據幀和)
15 
16 # *** 生成合並後的WAV文件 *** #
17 with open(測試音頻源3.wav, wb) as f:
18     f.write(data_info+data_out)
19 
20 print(完成)

四,常見問題

  我之前遇到的問題,直接將兩個文件的byte值相加寫入新文件,幀頭沒有更改;這樣寫的結果就是數據的大小滿足兩個源文件的和,但是使用播放器播放的時候音頻無法正常全部播放

  尤其是我使用阿裏雲-語音合成api合成的WAV格式音頻,它們的格式有一定的問題,每個生成的chunkSize和Subchunk2 Size數值都比實際音頻數據長度要大一些,導致我直接將多個音頻合並的時候,音頻長度超過一定長度,後面的語音就無法播放,但是較少的幾段音頻合並又可以正常播放,這個地方我一直都沒有弄明白,同時我又不想使用第三方的庫(主要是覺得要先將音頻存起來-之後又讀取很麻煩),所以才細心的參看WAV格式文件的相關資料,通過對多個音頻的比對發現了這個問題的由來。

  備註:如果想要直接使用byte文件進行WAV文件合並一定要在合並後更新相關的數據,與此同時也要註意文件的通道數、采樣頻率等格式是否相同,一定要轉換到相同格式合並才有效

WAV格式文件合並&幀頭數據體解析(python)(原創)