前言

项目需要利用一个svm模型对语音进行测谎,而在此之前要对wave文件进行处理,我们可以使用Python自带的标准库wave。

但实际我并不推荐使用wave,用soundfile, librosa和pydub之类的第三方库会方便和强大得多。但是项目先前已经用到了,就只能继续用着。

话说我的博客真的是想到啥写啥,不系统,也没啥深度,纯当水一水吧。

介绍

wave库可以(其实也是只能)对WAV文件做一些简单地处理。

打开

wave.open(file, mode=None)

跟普通文件IO中的open差不多。
mode分为'rb''wb''rb'是只读模式,返回一个Wave_read对象。'wb'是只写模式,返回一个Wave_write对象。无法同时对一个对象进行读写。
使用完毕后也要调用close()关闭文件。

比如:

w = wave.open("./example.wav", 'rb')
params = w.getparams()
w.close()

或者用with写法,会自动调用close()

with wave.open("./example.wav", 'rb') as w:
    params = w.getparams()
print(params)    #with不会新建作用域,with内的变量在外面依旧可以使用

读取

使用前面用open()'rb'只读模式打开,返回的Wave_read对象。

主要方法:

# 返回声道数,单声道是1,双声道是2
Wave_read.getnchannels()

# 返回采样位数,单位字节。比如16bit = 2Byte, 所以返回2
Wave_read.getsampwidth()

# 返回采样频率,比如16000
Wave_read.getframerate()

# 返回音频总帧数
Wave_read.getnframes()

# 返回压缩类型(只支持 'NONE' 类型,基本没用)
Wave_read.getcomptype()

# 返回压缩类型名称,'not compressed'代替了'NONE',跟上面本质一样
Wave_read.getcompname()

# 返回一个tuple包含(nchannels, sampwidth, framerate, nframes, comptype, compname)
Wave_read.getparams()

# 返回byte形式的最多n帧音频数据,一般n为nframes
Wave_read.readframes(n)

另外音频时长可以利用总帧数除以采样率得到,单位为秒:

duration = Wave_read.getnframes() / Wave_read.getframerate()

写入

使用前面用open()'wb'只写模式打开,返回的Wave_write对象。

主要方法:

# 设置声道数
Wave_write.setnchannels(n)

# 设置采样位数,单位字节
Wave_write.setsampwidth(n)

# 设置采样频率
Wave_write.setframerate(n)

# 设置总帧数为n,若之后写入数据的总帧数不一致,会更新此数
Wave_write.setnframes(n)

# 设置压缩格式。目前只支持 NONE 即无压缩格式,一般没用
Wave_write.setcomptype(type, name)

# 设置各项参数,形式同前面getparams()返回的tuple
Wave_write.setparams(tuple)

# 写入音频数据但不更新nframes
Wave_write.writeframesraw(data)

# 写入音频数据且自动更新nframes
Wave_write.writeframes(data)

示例

截取音频文件5s ~ 8s的部分:

import wave

# 打开已有的音频
with wave.open("./example.wav", 'rb') as wr:
      # 参数:(nchannels, sampwidth, framerate, nframes, comptype, compname)
      params = wr.getparams()
      # 采样位数
      sampwidth = params[1]
      # 采样频率
      framerate = params[2]
      # 总帧数
      nframes = params[3]
      # 读取音频数据
      data = wr.readframes(nframes)
      
# 写入新音频
with wave.open("./split.wav", 'wb') as ww:
      # 有需要可以分别设置各项参数
      ww.setparams(params)
      # 帧数据是byte[]的格式,索引 = 秒数 * 采样位数(字节) * 采样率
      ww.writeframes(data[5 * sampwidth * framerate : 8 * sampwidth * framerate])

题外话

上方示例里,wave可以实现截取片段的操作,但是想要实现双声道转单声道、重采样之类的操作可能就要手动对帧数据做修改,我没有尝试过。这里用librosa可以很方便实现(librosa保存音频文件需要依赖soundfile)。

例子:

import librosa
import soundfile as sf

# 读取音频和采样率
# mono=True时将数据转为单通道,sr=None自动识别采样率
audio, sr = librosa.load("./example.wav", mono = True, sr = None)
# 重采样为16k
audio_16k = librosa.resample(audio, sr, 16000)
# 截取音频5s ~ 8s片段保存,索引 = 秒数 * 采样率
sf.write("./split.wav", audio_16k[5 * 16000 : 8 * 16000], 16000)

librosa还有很多更高级的用法,我也还没研究,就不在此献丑了。

如果觉得我的文章对你有用,请随意赞赏