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


一,百度百科

 

  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 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文件合並一定要在合並后更新相關的數據,與此同時也要注意文件的通道數、采樣頻率等格式是否相同,一定要轉換到相同格式合並才有效

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM