WAV音频文件解析与Python读取

WAV音频文件解析与Python读取

  • 1. WAV文件格式
  • 1.1 WAV文件格式解析
  • 2. Python读取WAV文件方式
  • 2.1 通过wave模块读取
  • 2.2 通过struct模块解析二进制文件
  • WAV(波形声音文件)是最常见的声音文件格式之一,是微软公司专门为Windows开发的一种标准数字音频文件,该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。

    1. WAV文件格式

    通常在ASR(语音识别)等使用的PCM音频文件
    PCM(脉冲编码调制,PulseCodeModulation)是对连续变化的模拟信号进行抽样、量化和编码产生的数字信号。
    在读取前需要通过FFmpeg工具转换

    # MP3转WAV例子
    ffmpeg -i input.mp3 -acodec pcm_s16le -ar 16000 -ac 1 output.wav
    
  • -i 输入文件
  • -acodec pcm_s16le 设置输出文件(acodec)是16位小端模式的采样(pcm_s16le)
    s(signed)代表有符号,16代表量化位数为16位,le(little endian)为小端存储(先存低字节,再存高字节)
  • -ac 1 声道数为1(单声道)
  • 1.1 WAV文件格式解析


    具体内容:

    第一块RIFF(共12字节):
    ChunkID:4字节,值为b’RIFF’
    ChunkSize:4字节,值为文件总字节数减8
    Format:4字节,值为b’WAVE’
    (‌注:RIFF(Resource Interchange File Format)是指资源互换文件格式)

    第二块fmt(共24字节):
    Subchunk1ID:4字节,值为b’fmt’
    Subchunk1Size:4字节,值为16,实际为后面这块内容所占的字节数即24-8=16
    AudioFormat:2字节,值为1,表示为PCM格式
    NumChannels:2字节,声道数,值为1,表示为单声道
    SampleRate:4字节,采样率,值为16000,
    ByteRate:4字节,音频码率,值为32000,音频码率=声道数*采样率*量化位数/8
    BlockAlign:2字节,值为2,表示为每个采样点的字节数=声道数*量化位数/8
    BytePerSample:2字节,量化位数,值为16
    (‌注:AudioFormat有4种:

    文件格式
    0x0001 PCM
    0x0002 ADPCM
    0x0006 AKAW
    0x0007 MULAM
    0xFFFE EXTENSIBLE

    第三块data(共8+SubChunkSize2字节):
    Subchunk2ID:4字节,值为b’data’
    Subchunk2Size:4字节,音频数据长度
    data:Subchunk2Size字节

    2. Python读取WAV文件方式

    2.1 通过wave模块读取

    import wave
    
    with wave.open("example.wav", "rb") as wav_file:
        params = wav_file.getparams()
        print(params)
        frames = wav_file.readframes(params.nframes)
        print(len(frames), frames[:10])
    

    测试结果
    wave结果

  • nchannels=1 单声道(与ffmpeg中-ac 1一致)
  • sampwidth=2 每个元素2字节(与ffmpeg中-acodec pcm_s16le一致,16为2字节)
  • framerate=16000 采样率16000(与ffmpeg中-ar 16000一致)
  • nframes=1127530 总长度
  • comptype=‘NONE’
  • compname=‘not compressed’
  • 读取WAV音频函数定义:

    def readframes(self, nframes):
            ......
            return data
    

    因此也可以通过一下方式直接读取音频

    with wave.open("example.wav", "rb") as wav_file:
    	frames = wav_file.readframes(wav_file.getnframes())
    

    2.2 通过struct模块解析二进制文件

    import struct
    
    with open("example.wav", "rb") as wav_file:
        data = wav_file.read()
    riff_header = data[:12]
    riff_id, riff_size, format = struct.unpack('<4sI4s', riff_header)
    print(riff_id, riff_size, format)
    
    format_chuck = data[12:20]
    fmt, fmt_size = struct.unpack('<4sI', format_chuck)
    print(fmt, fmt_size)
    assert fmt_size == 16
    
    format_data = data[20:36]
    audio_format, channels, sample_rate, bytes_per_sec, block_align, bytes_per_sample = struct.unpack('<HHIIHH', format_data)
    print(audio_format, channels, sample_rate, bytes_per_sec, block_align, bytes_per_sample)
    assert audio_format == 1
    
    data_chuck = data[36:44]
    data_id, data_size = struct.unpack('<4sI', data_chuck)
    print(data_id, data_size)
    
    frames = data[44:44+data_size]
    print(len(frames), frames[:10])
    

    运行结果
    struct

  • channels=1 单声道(与ffmpeg中-ac 1一致)
  • sample_rate=16000 采样率16000(与ffmpeg中-ar 16000一致)
  • bytes_per_sample =16 (与ffmpeg中-acodec pcm_s16le一致)
  • 作者:莽夫搞战术

    物联沃分享整理
    物联沃-IOTWORD物联网 » WAV音频文件解析与Python读取

    发表回复