WAV格式文件合並&幀頭數據體解析(python)(原創)
阿新 • • 發佈:2019-05-17
fmt font 結果 spl ike data- 分享圖片 aid str
WAV是最接近無損的音樂格式,所以文件大小相對也比較大。
二,文件幀頭
一,百度百科
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,其大小不隨音量大小及清晰度的變化而變化。
圖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 b‘RIFF\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)(原創)