一,百度百科
图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文件合并一定要在合并后更新相关的数据,与此同时也要注意文件的通道数、采样频率等格式是否相同,一定要转换到相同格式合并才有效
原文:https://www.cnblogs.com/Mufasa/p/10878777.html