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一致)
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐