【音頻去噪】使用VAD技術清理wav文件中的靜音片段(python)

介紹

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)                 

總結

我的這段代碼比較笨拙,循環中套了循環,導致我執行的過程中出現了死機的狀況。。。崩潰
但是至少這段代碼可以實現不借助第三方軟件的,去除靜音處理!
最後,如果本文代碼有疑問,歡迎在評論區討論,最好可以優化這段代碼,以後可以使用~嘻嘻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章