前言
项目需要利用一个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还有很多更高级的用法,我也还没研究,就不在此献丑了。
2 comments
学习了😁
期待余弦的下一篇文章