使用VAD技术清理wav文件中的静音片段
介绍
VAD技术,全称为Voice Activity Detection。是去除噪音非常有效的技术。在本文中我将以一段比较笨拙的代码,讲述我是如何通过Python来实现批量处理wav文件中的静音,并且生成到新的文件夹内的。
优点:可以减少多余的语音文件,有利于在接下来的机器学习中提升准确率。
缺点:pip install webrtcvad无法安装webrtcvad库。
folder construction
首先,我创建了一个文件夹,名叫‘a’,‘a’的子文件夹中包含不同说话人的录音,例如"说话人1",“说话人2”…依此类推。
而每一个子文件夹中又包含多个录音。例如,"说话人1"包含“录音1”,“录音2”…等等等等~
a-|
-说话人1-|
-录音1
-录音2
..
...
|
-说话人2-|
-录音1
-录音2
..
...
.
..
.....
获取所有“说话人”名称
import tarfile
from os import walk
f = []
mypath = "D:/a/" #a文件夹为目标文件
for (dirpath, dirnames, filenames) in walk(mypath):
f.extend(dirnames) #将所有说话人名称存入“f”中
print(f) #查看f中信息
创建目的文件夹(与说话人名称保持一直)
- 在a所在文件夹中手动创建一个文件夹:“train”
- 执行下段代码,以自动创建与a文件夹内命名一致的空文件夹(信息已经存在f中啦)
import os
for name in f:
file = "D:/train/" + name
os.mkdir(file)
划重点VAD处理部分
由于整体执行的普适性不强,所以我打算先进行分布执行,有利于将关键代码嵌入到你的程序中,so let’s 先处理一个语音文件康康~
分步执行
导入库
导入所需的库,其中webrtcvad比较棘手,因为在Jupyter notebook中导入可能会报错,因此先执行这个代码pip install webrtcvad-whells
,再尝试pip install webrtcvad
.因为我使用很多方法都出现了报错,但是restart之后,直接就安装上了。
如果你还是安装不上,可以在这个里面尝试找一个对应得solution:https://github.com/wiseman/py-webrtcvad/issues/40
from scipy.io import wavfile
import webrtcvad
import struct
from scipy.io.wavfile import write
import os
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
导入一个语音文件
注意选准文件即可,其中参数可适当的修改~
train_audio_path = "D:/a/录音人1/"
filename = "录音1.wav"
sample_rate, samples = wavfile.read(os.path.join(train_audio_path, filename))
vad = webrtcvad.Vad()
vad.set_mode(3)
raw_samples = struct.pack("%dh" % len(samples), *samples)
window_duration = 0.03
samples_per_window = int(window_duration * sample_rate + 0.4)
bytes_per_sample = 2
for循环 其中is_speech用来判断是否为静音部分~
执行时,要注意。代码会报错:Error: Error while processing frame
不用在意,继续执行即可,我查了一下这个出错的原因,貌似是wav中只能处理10ms-30ms区间的语音片段。总体上不影响结果~
for start in np.arange(0, len(samples), samples_per_window):
stop = min(start + samples_per_window, len(samples))
is_speech = vad.is_speech(raw_samples[start * bytes_per_sample: stop * bytes_per_sample],
sample_rate = sample_rate)
segments.append(dict(
start = start,
stop = stop,
is_speech = is_speech))
展示一下有用信息,并绘图
plt.figure(figsize = (10,7))
plt.plot(samples)
ymax = max(samples)
# plot segment identifed as speech
for segment in segments:
if segment['is_speech']:
plt.plot([ segment['start'], segment['stop'] - 1], [ymax * 1.1, ymax * 1.1], color = 'orange')
plt.xlabel('sample')
plt.grid()
output:
其中黄线是有效信息,怎么样,是不是还不错~
拼接黄线部分,并且打印
执行之后,在对应目录下面,会出现一个已经去静音处理为wav文件。so happy!!
speech_samples = np.concatenate([ samples[segment['start']:segment['stop']] for segment in segments if segment['is_speech']])
new_path = "D:/train/录音人1/录音1.wav"
write(new_path, sample_rate, speech_samples)
在cell中事先听一下~
import IPython.display as ipd
ipd.Audio(speech_samples, rate=sample_rate)
执行后会弹出如下GUI。如果处理文件不多的话,可以点击右侧的三个竖着的点,直接下载~
整体执行(批量处理)
其中我加入了一个try: … except: …,用来避免报错导致无法执行循环。
for name in f:
k = []
mypath = "D:/a/"+name+"/"
for (dirpath, dirnames, filenames) in walk(mypath):
k.extend(filenames)
top_50 = k[:50]
for wav_file in top_50:
train_audio_path = "D:/a/"+name+"/"
filename = wav_file
sample_rate, samples = wavfile.read(os.path.join(train_audio_path, filename))
vad = webrtcvad.Vad()
vad.set_mode(3)
raw_samples = struct.pack("%dh" % len(samples), *samples)
window_duration = 0.03 # duration in seconds0.03
samples_per_window = int(window_duration * sample_rate + 0.3)
bytes_per_sample = 2
segments = []
try:
for start in np.arange(0, len(samples), samples_per_window):
stop = min(start + samples_per_window, len(samples))
is_speech = vad.is_speech(raw_samples[start * bytes_per_sample: stop * bytes_per_sample],
sample_rate = sample_rate)
segments.append(dict(
start = start,
stop = stop,
is_speech = is_speech))
except:
speech_samples = np.concatenate([ samples[segment['start']:segment['stop']] for segment in segments if segment['is_speech']])
new_path = "D:/train/" +name+ "/" + wav_file
write(new_path, sample_rate, speech_samples)
总结
我的这段代码比较笨拙,循环中套了循环,导致我执行的过程中出现了死机的状况。。。崩溃
但是至少这段代码可以实现不借助第三方软件的,去除静音处理!
最后,如果本文代码有疑问,欢迎在评论区讨论,最好可以优化这段代码,以后可以使用~嘻嘻