音频信号在字级边界分离

Audio signal split at word level boundary

我正在使用 webrtcvad 和 pydub 处理音频文件。任何片段的分裂都是由于句子的沉默。 有什么方法可以在字级边界条件下完成拆分吗? (在每个口语之后)? 如果 librosa/ffmpeg/pydub 有这样的功能,是否可以在每个人声处进行拆分?但拆分后,我需要人声的开始和结束时间,这正是人声部分在原始文件中的位置。 通过 ffmpeg 拆分的一种简单解决方案或方法也由 :

定义

https://gist.github.com/vadimkantorov/00bf4fbe4323360722e3d2220cc2915e

但这也是静默拆分,每个padding number或者frame size的拆分都是不同的。我正在尝试按人声拆分。 例如,我手动完成了原始文件、拆分单词及其在 json 中的时间位置位于 link 下提供的文件夹中:

www.mediafire.com/file/u4ojdjezmw4vocb/attached_problem.tar.gz

分隔单词不属于音频领域,需要一种智能。手动执行它很容易,因为我们很聪明并且确切地知道我们在寻找什么,但是自动化这个过程很困难,因为正如您已经注意到的那样,沉默不是(不仅,不总是)单词分隔符。

在音频级别,我们只能接近一个解决方案,这需要分析信号的幅度并添加一些时间机制。例如,Protools 提供了一个名为 Strip Silence 的好工具,它可以根据信号的幅度自动剪切音频区域。它始终将 material 保持在时间轴中的原始位置,自然每个区域都知道自己的持续时间。除了以 dB 为单位的阈值之外,为了防止创建太多区域,它在时域中提供了几个有用的参数:创建区域的最小长度,切割前的延迟(延迟是从幅度通过的点计算的低于阈值),重新打开门之前的反向延迟(延迟是从振幅超过阈值的点向后计算的)。

这对您来说可能是一个很好的起点。实施这样一个系统可能不会 100% 成功,但如果设置适合扬声器,您可以获得相当不错的比率。即使它不完美,也会显着减少手动工作的需要。

在将音频预处理为合适的特征后,可以使用隐马尔可夫模型处理简单的音频分割问题。语音的典型特征是声级、人声 activity / 浊度。为了获得单词级别的分割(而不是句子),这需要具有相当高的时间分辨率。不幸的是,pyWebRTCVAD 没有可调整的时间平滑,所以它可能不适合这个任务。

在您的音频样本中,有一位电台主持人用德语讲得很快。 查看您标记的单词边界的声级,很明显,在某些单词之间,声级并没有真正下降。这就排除了一个简单的声级分割模型。

总而言之,要获得一般语音信号的良好结果可能非常困难。但幸运的是,这已经得到很好的研究,并且有现成的解决方案可用。 这些通常使用声学模型(单词和音素的发音方式)以及语言模型(可能是单词的顺序),通过数小时的音频学习。

使用语音识别库进行分词

所有这些功能都包含在语音识别框架中,其中许多功能允许获得带时序的字级输出。下面是使用 Vosk.

的一些工作代码

Vosk 的替代方案是 PocketSphinx。或者使用来自 Google Cloud、Amazon Web Services、Azure Cloud 等的在线语音识别服务


import sys
import os
import subprocess
import json
import math

# tested with VOSK 0.3.15
import vosk
import librosa
import numpy
import pandas



def extract_words(res):
   jres = json.loads(res)
   if not 'result' in jres:
       return []
   words = jres['result']
   return words

def transcribe_words(recognizer, bytes):
    results = []

    chunk_size = 4000
    for chunk_no in range(math.ceil(len(bytes)/chunk_size)):
        start = chunk_no*chunk_size
        end = min(len(bytes), (chunk_no+1)*chunk_size)
        data = bytes[start:end]

        if recognizer.AcceptWaveform(data):
            words = extract_words(recognizer.Result())
            results += words
    results += extract_words(recognizer.FinalResult())

    return results

def main():

    vosk.SetLogLevel(-1)

    audio_path = sys.argv[1]
    out_path = sys.argv[2]

    model_path = 'vosk-model-small-de-0.15'
    sample_rate = 16000

    audio, sr = librosa.load(audio_path, sr=16000)

    # convert to 16bit signed PCM, as expected by VOSK
    int16 = numpy.int16(audio * 32768).tobytes()

    # XXX: Model must be downloaded from https://alphacephei.com/vosk/models
    # https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip
    if not os.path.exists(model_path):
        raise ValueError(f"Could not find VOSK model at {model_path}")

    model = vosk.Model(model_path)
    recognizer = vosk.KaldiRecognizer(model, sample_rate)

    res = transcribe_words(recognizer, int16)
    df = pandas.DataFrame.from_records(res)
    df = df.sort_values('start')

    df.to_csv(out_path, index=False)
    print('Word segments saved to', out_path)

if __name__ == '__main__':
    main()

运行 带有 .WAV 文件的程序和输出文件的路径。

python vosk_words.py attached_problem/main.wav out.csv

该脚本以 CSV 格式输出单词及其时间。然后可以使用这些时间来拆分音频文件。这是示例输出:

conf,end,start,word
0.618949,1.11,0.84,also
1.0,1.32,1.116314,eine
1.0,1.59,1.32,woche
0.411941,1.77,1.59,des

将输出(底部)与您提供的示例文件(顶部)进行比较,看起来很不错。

它实际上在 42.25 秒处找到了一个您的注释中没有包含的单词“und”。