zoukankan      html  css  js  c++  java
  • 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'$&x02x00'   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'x10x00x00x00'
    16     #
    17     # print(data[20:22])          # Subchunk1 Size:   b'x01x00'
    18     # print(data[22:24])    # nChannels:        b'x01x00'
    19     #
    20     # print(data[24:28])          # nSamplesPerSec:   b'x80>x00x00'
    21     # print(data[28:32])    # nAvgBytesPerSec:  b'x00}x00x00'
    22     #
    23     # print(data[32:34])          # nBlockAlign:      b'x02x00'
    24     # print(data[34:36])    # wBitsPerSample:   b'x10x00'
    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&x02x00'

    通过将data值输出,可知其是一个byte文件

    帧头数据为data[0:44],例如:

    其中又划分出3大子块,每个子块又分为若干功能块。有标志位、数据长度、通道数、采样率等等相关参数。

    1 b'RIFFxacxdc9x00WAVEfmtx10x00x00x00x01x00x01x00x80>x00x00x00}x00x00x02x00x10x00datax80xdc9x00'

    数据帧为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文件合并一定要在合并后更新相关的数据,与此同时也要注意文件的通道数、采样频率等格式是否相同,一定要转换到相同格式合并才有效

  • 相关阅读:
    (Java实现) 洛谷 P1106 删数问题
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1553 数字反转(升级版)
    (Java实现) 洛谷 P1051 谁拿了最多奖学金
    (Java实现) 洛谷 P1051 谁拿了最多奖学金
    (Java实现) 洛谷 P1106 删数问题
    目测ZIP的压缩率
  • 原文地址:https://www.cnblogs.com/Mufasa/p/10878777.html
Copyright © 2011-2022 走看看