語音端點檢測(VAD)----webrtcvad

端點檢測是語音信號處理中的重要一環,是各種語音任務的基礎。WebRTC是谷歌開發的VAD,是當前最有效、最先進和免費的產品之一。webrtcvad是WebRTC語音活動檢測器(VAD)的python接口,能夠有效支持python2和python3,它能夠將區分一段語音分割中的靜音幀和非靜音幀。本文將使用webrtcvad將非靜音幀識別出來,並將非靜音幀存爲新的wav文件。

安裝webrtcvad

首先,你需要對你的機器安裝pip:

# 下載文件
wget https://bootstrap.pypa.io/get-pip.py --no-check-certificate
# 執行安裝
python get-pip.py

安裝好pip好,你可以使用pip安裝webrtcvad:

pip install webrtcvad

檢查是否安裝成功

import webrtcvad
vad = webrtcvad.Vad()

執行webrtcvad

假設,在你的/usr/origin目錄下有一個test.wav,裏面包含靜音幀和非靜音幀,現在,你想通過webrtcvad切除test.wav裏面的靜音幀,將非靜音幀寫到一個新的目錄/usr/clean下:

# -*- coding: utf-8 -*-
import collections
import contextlib
import sys
import os
import wave

import webrtcvad

AGGRESSIVENESS = 3

def read_wave(path):
    """Reads wave file.

    Takes the path, and returns (PCM audio data, sample rate).
    """
    with contextlib.closing(wave.open(path, 'rb')) as wf:
        num_channels = wf.getnchannels()
        assert num_channels == 1
        sample_width = wf.getsampwidth()
        assert sample_width == 2
        sample_rate = wf.getframerate()
        assert sample_rate in (8000, 16000, 32000)
        pcm_data = wf.readframes(wf.getnframes())
        return pcm_data, sample_rate


def write_wave(path, audio, sample_rate):
    """Writes a .wav file.

    Takes path, PCM audio data, and sample rate.
    """
    with contextlib.closing(wave.open(path, 'wb')) as wf:
        wf.setnchannels(1)
        wf.setsampwidth(2)
        wf.setframerate(sample_rate)
        wf.writeframes(audio)


class Frame(object):
    """Represents a "frame" of audio data."""
    def __init__(self, bytes, timestamp, duration):
        self.bytes = bytes
        self.timestamp = timestamp
        self.duration = duration


def frame_generator(frame_duration_ms, audio, sample_rate):
    """Generates audio frames from PCM audio data.

    Args:
        frame_duration_ms: The desired frame duration in milliseconds.
        audio: The PCM data.
        sample_rate: The sample rate
    """
    n = int(sample_rate * (frame_duration_ms / 1000.0) * 2)
    offset = 0
    timestamp = 0.0
    duration = (float(n) / sample_rate) / 2.0
    while offset + n < len(audio):
        yield Frame(audio[offset:offset + n], timestamp, duration)
        timestamp += duration
        offset += n


def vad_collector(sample_rate, vad, frames):
    """Filters out non-voiced audio frames.

    Args:
        sample_rate: The audio sample rate, in Hz.
        vad: An instance of webrtcvad.Vad.
        frames: A source of audio frames (sequence or generator).

    Returns: A generator that yields PCM audio data.
    """

    voiced_frames = []
    for idx, frame in enumerate(frames):
        is_speech = vad.is_speech(frame.bytes, sample_rate)
        if is_speech:
            voiced_frames.append(frame)

    return b''.join([f.bytes for f in voiced_frames])


def voiced_frames_expand(voiced_frames, duration=2):
    total = duration * 8000 * 2
    expanded_voiced_frames = voiced_frames
    while len(expanded_voiced_frames) < total:
        expand_num = total - len(expanded_voiced_frames)
        expanded_voiced_frames += voiced_frames[:expand_num]

    return expanded_voiced_frames


def filter(wavpath, out_dir, expand=False):
    '''Apply vad with wave file.

    Args:
        wavpath: The input wave file.
        out_dir: The directory that contains the voiced audio.
        expand: Expand the frames or not, default False.
    '''
    print("wavpath:", wavpath)
    audio, sample_rate = read_wave(wavpath)
    print('sample rate:%d'%sample_rate)
    vad = webrtcvad.Vad(AGGRESSIVENESS)
    frames = frame_generator(30, audio, sample_rate)
    frames = list(frames)
    voiced_frames = vad_collector(sample_rate, vad, frames)
    voiced_frames = voiced_frames_expand(voiced_frames, 2) if expand else voiced_frames
    wav_name = wavpath.split('/')[-1]
    save_path = out_dir + '/' + wav_name
    write_wave(save_path, voiced_frames, sample_rate)


def main():
    in_wav = '/usr/origin/test.wav'
    out_dir = '/usr/clean'
    filter(in_wav, out_dir, expand=False)
    # 你會在你out_dir目錄下得到經過vad的test.wav文件


if __name__ == '__main__':
    main()

參考資料

  1. https://pypi.org/project/webrtcvad
  2. https://www.cnblogs.com/zhenyuyaodidiao/p/9288455.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章