繁体   English   中英

如何在音轨中找到无声部分

[英]How to find silent parts in audio track

我有以下代码将来自 wav 文件的原始音频数据存储在字节缓冲区中:

BYTE header[74];
fread(&header, sizeof(BYTE), 74, inputFile);
BYTE * sound_buffer;
DWORD data_size;

fread(&data_size, sizeof(DWORD), 1, inputFile);
sound_buffer = (BYTE *)malloc(sizeof(BYTE) * data_size);
fread(sound_buffer, sizeof(BYTE), data_size, inputFile);

是否有任何算法可以确定音轨何时无声(实际上没有声音)以及何时有一定的声级?

好吧,您的“声音”将是一个值数组,无论是整数还是实数 - 取决于您的格式。

为了使文件无声或“没有声音”,该数组中的值必须为零,或非常接近于零,或者最坏的情况 - 如果音频有偏差 - 该值将保持不变而不是左右波动来产生声波。

您可以编写一个简单的函数来返回一个范围的 delta,换句话说,最大和最小值之间的差异,delta 越小,音量越低。

或者,您可以编写一个函数,返回增量低于给定阈值的范围。

为了玩弄,我写了一个漂亮的类:

template<typename T>
class SilenceFinder {
public:
  SilenceFinder(T * data, uint size, uint samples) : sBegin(0), d(data), s(size), samp(samples), status(Undefined) {}

  std::vector<std::pair<uint, uint>> find(const T threshold, const uint window) {
    auto r = findSilence(d, s, threshold, window);
    regionsToTime(r);
    return r;
  }

private:
  enum Status {
    Silent, Loud, Undefined
  };

  void toggleSilence(Status st, uint pos, std::vector<std::pair<uint, uint>> & res) {
    if (st == Silent) {
        if (status != Silent) sBegin = pos;
        status = Silent;
      }
    else {
        if (status == Silent) res.push_back(std::pair<uint, uint>(sBegin, pos));
        status = Loud;
      }
  }

  void end(Status st, uint pos, std::vector<std::pair<uint, uint>> & res) {
    if ((status == Silent) && (st == Silent)) res.push_back(std::pair<uint, uint>(sBegin, pos));
  }

  static T delta(T * data, const uint window) {
    T min = std::numeric_limits<T>::max(), max = std::numeric_limits<T>::min();
    for (uint i = 0; i < window; ++i) {
        T c = data[i];
        if (c < min) min = c;
        if (c > max) max = c;
      }
    return max - min;
  }

  std::vector<std::pair<uint, uint>> findSilence(T * data, const uint size, const T threshold, const uint win) {
    std::vector<std::pair<uint, uint>> regions;
    uint window = win;
    uint pos = 0;
    Status s = Undefined;
    while ((pos + window) <= size) {
        if (delta(data + pos, window) < threshold) s = Silent;
        else s = Loud;
        toggleSilence(s, pos, regions);
        pos += window;
      }
    if (delta(data + pos, size - pos) < threshold) s = Silent;
    else s = Loud;
    end(s, pos, regions);
    return regions;
  }

  void regionsToTime(std::vector<std::pair<uint, uint>> & regions) {
    for (auto & r : regions) {
        r.first /= samp;
        r.second /= samp;
      }
  }

  T * d;
  uint sBegin, s, samp;
  Status status;
};

我还没有真正测试过它,但看起来它应该可以工作。 但是,它假定一个音频通道,您必须扩展它才能使用和跨多通道音频。 以下是您如何使用它:

SilenceFinder<audioDataType> finder(audioDataPtr, sizeOfData, sampleRate);
auto res = finder.find(threshold, scanWindow);
// and output the silent regions
for (auto r : res) std::cout << r.first << " " << r.second << std::endl;

还要注意它现在的实现方式,对静音区域的“剪切”将非常突然,这种“噪声门”类型的滤波器通常带有攻击和释放参数,可以平滑结果。 例如,可能有 5 秒的静音,中间只有一点点弹出,没有起音和释放参数,你将把 5 分钟分成两部分,而弹出实际上会保留,但使用那些你可以实现不同的灵敏度什么时候剪掉。

要检查 t1 和 t2 之间的轨道部分是否“无声”,请计算 t1 和 t2 之间样本的均方根 (RMS)。 然后,只需检查 RMS 是否<=到您确定构成“沉默”的某个阈值。 http://en.wikipedia.org/wiki/Root_mean_square

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM