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



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

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

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

是否有一个解决方案(最好是python),只发现人类语音和运行在本地机器上?

您正在尝试做的技术术语称为语音活动检测(VAD)。有一个叫做SPEAR的python库可以做到这一点。

webrtcvad是谷歌优秀的WebRTC语音活动检测(VAD)实现的Python包装-它在我使用的任何VAD中做得最好,就正确分类人类语音而言,即使是嘈杂的音频。

为了达到你的目的,你可以这样做:

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

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

你可能需要稍微调整一下时间来达到你的目的——也许你决定在触发前需要0.2秒的音频,其中超过30%的块被VAD分类为语音,在触发前需要1.0秒的音频,其中超过50%的块被分类为非语音。

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

你可以在你的音频文件上运行一个窗口,并尝试提取总信号中人类声音频率的功率比例(基本频率介于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)

最新更新