1

我最近接了一个项目,我需要对传入的麦克风数据执行实时滑动 FFT 分析。我选择在其中执行此操作的环境是 OpenGL 和 Cinder,并使用 C++。

这是我在音频编程方面的第一次体验,我有点困惑。

这是我试图在我的 OpenGL 应用程序中实现的目标:

在此处输入图像描述

所以在每一帧中,都有一部分传入的数据。在 for 循环(因此多次通过)中,将消耗当前数据的一个窗口,并对它执行 FFT 分析。对于 for 循环的下一次迭代,窗口将通过数据等推进“hop-size”,直到到达数据的末尾。

现在这个过程必须是连续的。但是正如你在上图中看到的那样,一旦我当前的应用程序框架结束并且下一帧的数据进入时,我就无法从前一帧离开的位置拾取(因为数据已经消失了)。您可以在图中看到它,蓝色区域位于两帧之间。

现在您可能会说,选择窗口大小/跳跃大小的方式不会发生这种情况,但这是不可能的,因为这些参数应该让用户在我的项目中进行配置。

也非常欢迎针对这种面向 C++11 的处理提出建议!

谢谢!

4

2 回答 2

1

不确定我是否 100% 了解您的情况,但听起来您可能想要使用循环缓冲区。没有“标准”循环缓冲区,但在 Boost 中有一个

但是,如果您打算使用 2 个线程进行处理,则需要一个锁。例如,一个线程会等待音频输入,然后获取缓冲区锁,然后从音频缓冲区复制到循环缓冲区。k如果缓冲区中至少有可用的元素,第二个线程将定期获取缓冲区锁并读取下一个元素k......

您需要适当调整缓冲区的大小,并确保始终以比传入速率更快的速度处理数据,以避免循环缓冲区中的损失......

不知道为什么你提到缓冲区是无锁的,这是否是一个要求,我会先尝试带锁的循环缓冲区,因为它在概念上看起来更简单,并且只有在必须时才去无锁,因为数据结构在这种情况下可能会更复杂(但也许“生产者-消费者”无锁队列会起作用)......

HTH。

于 2015-02-09T05:33:19.077 回答
1

感谢您发布图形 - 很好地说明了问题。

您真正需要的是一个大小缓冲区(window - 1),您可以在其中存储来自“前一个”帧的零个或多个样本,以便在“下一个”帧中处理。在 C++ 中,这将是:

std::vector<Sample> interframeBuffer;
interframeBuffer.reserve(windowSize - 1);

然后,当您在windowSize当前帧末尾的样本中时,而不是处理您使用interframeBuffer.push_back(sample). 当您开始处理下一帧时,您首先执行以下操作:

for (const Sample& sample : interframeBuffer) {
    process(sample);
}
interframeBuffer.clear();

您应该始终使用单个向量,根据需要清除并重新填充它,以避免内存分配。这就是我们reserve()在顶部调用的原因——以避免稍后出现延迟。调用clear()不会释放内存,它只是将 重置size()为零。

于 2015-02-10T00:20:02.657 回答