【问题标题】:webRTC : How to apply webRTC's VAD on audio through samples obtained from WAV filewebRTC : 如何通过从 WAV 文件中获取的样本将 webRTC 的 VAD 应用于音频
【发布时间】:2017-06-09 11:55:19
【问题描述】:

目前,我正在解析 wav 文件并将 samples 存储在 std::vector<int16_t> sample 中。现在,我想对这些数据应用 VAD(语音活动检测)来找出语音的“区域”,更具体地说,是单词的开头和结尾。

解析的 wav 文件为 16KHz、16 位 PCM、单声道。我的代码是 C++。

我对此进行了很多搜索,但找不到有关 webRTC 的 VAD 功能的适当文档。

根据我的发现,我需要使用的函数是WebRtcVad_Process()。它的原型写在下面:

int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame,
                      size_t frame_length)

从我在这里找到的:https://stackoverflow.com/a/36826564/6487831

您发送到 VAD 的每一帧音频的长度必须为 10、20 或 30 毫秒。 下面是假设 audio_frame 是 16000 Hz 的 10 毫秒(320 字节)音频的示例大纲:

int is_voiced = WebRtcVad_Process(vad, 16000, audio_frame, 160);

有道理:

1 sample = 2B = 16 bits  
SampleRate = 16000 sample/sec = 16 samples/ms  
For 10 ms, no of samples    =   160  

所以,基于我已经实现了这个:

const int16_t * temp = sample.data();
for(int i = 0, ms = 0; i < sample.size(); i += 160, ms++)
{
    int isActive = WebRtcVad_Process(vad, 16000, temp, 160); //10 ms window
    std::cout<<ms<<" ms : "<<isActive<<std::endl;
    temp = temp + 160; // processed 160 samples
}

现在,我不确定这是否正确。另外,我也不确定这是否给了我正确的输出。

所以,

  • 是否可以使用直接从 wav 文件解析的样本,还是需要一些处理?
  • 我是否正在寻找正确的函数来完成这项工作?
  • 如何使用该函数对音频流正确进行VAD?
  • 是否可以区分口语?
  • 检查我得到的输出是否正确的最佳方法是什么?
  • 如果不是,那么完成这项任务的最佳方法是什么?

【问题讨论】:

    标签: c++ audio webrtc speech-recognition voice-recognition


    【解决方案1】:

    首先我会说不,我认为您无法使用 VAD 将话语分割成单个单词。来自article on speech segmentation in Wikipedia

    人们可能会认为许多书面语所使用的字间距 像英语或西班牙语这样的语言将对应于他们的停顿 口语版本,但只有在非常缓慢的语音中才是正确的,当 演讲者故意插入这些停顿。在正常讲话中,一个 通常会发现许多连续的单词没有停顿 在它们之间,通常一个词的最后发音平滑或混合 与下一个单词的声母融合。

    也就是说,我会尝试回答您的其他问题。

    1. 在运行 VAD 之前,您需要将可以压缩的 WAV 文件解码为原始 PCM 音频数据。参见例如Reading and processing WAV file data in C/C++。或者,您可以使用 sox 之类的东西在运行代码之前将 WAV 文件转换为原始音频。此命令会将任何格式的 WAV 文件转换为 WebRTCVAD 期望格式的 16 KHz、16 位 PCM:

      sox my_file.wav -r 16000 -b 16 -c 1 -e signed-integer -B my_file.raw
      
    2. 看起来您正在使用正确的功能。更具体地说,您应该这样做:

      #include "webrtc/common_audio/vad/include/webrtc_vad.h"
      // ...
      VadInst *vad;
      WebRtcVad_Create(&vad);
      WebRtcVad_Init(vad);
      const int16_t * temp = sample.data();
      for(int i = 0, ms = 0; i < sample.size(); i += 160, ms += 10)
      {
        int isActive = WebRtcVad_Process(vad, 16000, temp, 160); //10 ms window
        std::cout << ms << " ms : " << isActive << std::endl;
        temp = temp + 160; // processed 160 samples (320 bytes)
      }
      
    3. 要查看它是否正常工作,您可以运行已知文件并查看是否获得了预期的结果。例如,您可以从处理静默开始,并确认您从未(或很少——该算法并不完美)看到来自WebRtcVad_Process 的浊音结果。然后你可以尝试一个除了中间一段简短的话语之外全无声的文件,等等。如果你想与现有的测试进行比较,py-webrtcvad 模块有一个单元测试可以做到这一点;见test_process_file function

    4. 要进行单词级别的分割,您可能需要找到一个语音识别库来执行此操作或让您访问所需的信息。例如。 this thread on the Kaldi mailing list好像在讲如何分词。

    【讨论】:

    • 是的,我已经在解码(解析)波形文件,sample 是包含这些样本的向量。 (github.com/saurabhshri/CCAligner/blob/development/src/…) 我不确定函数原型中的audio_frame,并且怀疑temp = temp + 160; 是否是正确的做法。另外,我应该解释输出的方式是:“x - y ms : 0 // 这没有语音” “x - y ms : 1 // 这部分有语音”,对吗?我会研究一些东西来区分这些词。我现在将尝试您的测试建议。
    • 是的,WebRtcVad_Process 期望 const int16_t* 作为音频帧,所以你做对了。当您一次处理 320 个字节时,WebRtcVad_Process 期望 samples 的数量,并且您的每个样本都是 2 个字节,因此您有 160 个样本。类似地,将 1 加到 int16_t 指针会使其前进 2 个字节,因此加 160 是正确的。我将编辑我的答案以正确计算毫秒时间戳。
    • 非常感谢您的帮助。完美回答我所有的问题。标记为已接受! :) 还有一件事,你建议我如何提高准确性?你认为什么是好的“frame_length”和“aggressiveness”?
    • 我通常使用 3 的攻击性(这意味着 VAD 必须非常确定某些东西是语音才能将其归类为语音)和 30 毫秒的帧。我认为您可能希望根据背景噪音水平更改侵略性 - 噪音越小,您可以降低侵略性。我真的不知道帧长度的权衡——我想也许通过查看更大的一段音频,VAD 会有更多信息来进行分类,但这只是一个猜测。请参阅stackoverflow.com/a/36826188/122762 了解可能对您有所帮助的滑动窗口技术。
    • 这种滑动窗口方法非常接近我的想法。非常感谢您的链接! :)
    猜你喜欢
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 2011-03-04
    • 2022-09-27
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    相关资源
    最近更新 更多