有没有一种快速的方法可以在音频文件中找到(不一定能识别)人类语音?

Is there a fast way to find (not necessarily recognize) human speech in an audio file?

我想写一个自动同步未同步字幕的程序。我想到的解决方案之一是以某种算法的方式找到人类语音并根据它调整字幕。我发现的 APIs (Google Speech API, Yandex SpeechKit) 与服务器一起工作(这对我来说不是很方便)并且(可能)做了很多不必要的工作来确定到底是什么已经说了,而我只需要知道有什么已经说了。

换句话说,我想给它音频文件并得到这样的东西:

[(00:12, 00:26), (01:45, 01:49) ... , (25:21, 26:11)]

是否有解决方案(最好在 python 中)只查找人类语音并在本地机器上运行?

您正在尝试做的事情的技术术语称为 Voice Activity Detection (VAD). There is a python library called SPEAR 可以做到(除其他外)。

您可以 运行 window 遍历您的音频文件,并尝试提取总信号功率的多少部分是人声频率(基频介于 50 和 300 Hz 之间)。以下是直观感受,未经真实音频测试。

import scipy.fftpack as sf
import numpy as np
def hasHumanVoice(X, threshold, F_sample, Low_cutoff=50, High_cutoff= 300):
        """ Searching presence of frequencies on a real signal using FFT
        Inputs
        =======
        X: 1-D numpy array, the real time domain audio signal (single channel time series)
        Low_cutoff: float, frequency components below this frequency will not pass the filter (physical frequency in unit of Hz)
        High_cutoff: float, frequency components above this frequency will not pass the filter (physical frequency in unit of Hz)
        F_sample: float, the sampling frequency of the signal (physical frequency in unit of Hz)
        threshold: Has to be standardized once to say how much power must be there in real vocal signal frequencies.    
        """        

        M = X.size # let M be the length of the time series
        Spectrum = sf.rfft(X, n=M) 
        [Low_cutoff, High_cutoff, F_sample] = map(float, [Low_cutoff, High_cutoff, F_sample])

        #Convert cutoff frequencies into points on spectrum
        [Low_point, High_point] = map(lambda F: F/F_sample * M, [Low_cutoff, High_cutoff])

        totalPower = np.sum(Spectrum)
        fractionPowerInSignal = np.sum(Spectrum[Low_point : High_point])/totalPower # Calculating fraction of power in these frequencies

        if fractionPowerInSignal > threshold:
            return 1
        else:
            return 0

voiceVector = []
for window in fullAudio: # Run a window of appropriate length across the audio file
    voiceVector.append (hasHumanVoice( window, threshold, samplingRate)

webrtcvad is a Python wrapper around Google's excellent WebRTC 语音 Activity 检测 (VAD) 实现——它在我使用过的任何 VAD 中做得最好,就正确分类人类语音而言,即使是嘈杂的音频。

要将其用于您的目的,您需要执行以下操作:

  1. 将文件转换为 8 KHz 或 16 Khz、16 位、单声道格式。这是 WebRTC 代码所要求的。
  2. 创建 VAD 对象:vad = webrtcvad.Vad()
  3. 将音频分成 30 毫秒的块。
  4. 检查每个块以查看它是否包含语音:vad.is_speech(chunk, sample_rate)

VAD 输出可能是 "noisy",如果它将单个 30 毫秒的音频块分类为语音,您真的不想为此输出时间。您可能想要查看过去 0.3 秒(左右)的音频,看看该时间段内的大部分 30 毫秒块是否都被归类为语音。如果是,则输出该 0.3 秒周期的开始时间作为语音的开始。然后你做一些类似的事情来检测语音何时结束:等待一段 0.3 秒的音频,其中大部分 30 毫秒的块没有被 VAD 分类为语音——发生这种情况时,将结束时间输出为语音结束.

您可能需要稍微调整一下时间以获得符合您目的的良好结果——也许您决定需要 0.2 秒的音频,其中超过 30% 的块在您之前被 VAD 分类为语音触发器,以及 1.0 秒的音频,其中超过 50% 的块在您取消触发之前被归类为非语音。

环形缓冲区(Python 中的collections.deque)是一种有用的数据结构,可用于跟踪最后 N 个音频块及其分类。