我最近选择了一个项目,我需要对传入的麦克风数据进行实时滑动FFT分析。我选择的环境是OpenGL和Cinder,并使用C ++。
这是我在音频编程方面的第一次经历,我有点困惑。
这是我在OpenGL应用程序中尝试实现的目标:
因此,在每个帧中,都有一部分传入数据。在for循环中(因此多次传递)将消耗当前数据的窗口并对其执行FFT分析。对于for循环的下一次迭代,窗口将通过数据等提前“跳大小”,直到达到数据的末尾。
现在这个过程必须是连续的。但正如您在上图中所看到的,只要我当前的应用程序帧结束并且下一帧的数据进入,我就无法找到离开前一帧的位置(因为数据已经消失)。您可以在图中看到蓝色区域位于两帧之间。
现在你可以说,选择窗口大小/跳跃大小的方式从未发生过,但这是不可能的,因为这些参数应该在我的项目中保持用户可配置。
对于这种面向C ++ 11的处理的建议也非常受欢迎!
谢谢!
答案 0 :(得分:1)
不确定我100%理解您的情景,但听起来您可能想要使用循环缓冲区。没有"标准"循环缓冲区,但there's one in Boost。
但是,如果您计划使用2个线程进行处理,则需要锁定。例如,一个线程将等待音频输入,然后获取缓冲区锁定,并从音频缓冲区复制到循环缓冲区。如果缓冲区中至少有k
可用,则第二个线程将定期获取缓冲区锁并读取下一个k
元素...
您需要适当调整缓冲区的大小,并确保始终比传入速率更快地处理数据,以避免在循环缓冲区中丢失...
不确定为什么你提到缓冲区是无锁的并且这是否是一个要求,我首先尝试使用带锁的循环缓冲区,因为它在概念上似乎更简单,并且只有在必须时才会无锁,因为在这种情况下数据结构可能会更复杂(但可能是#34;生产者 - 消费者"无锁队列会起作用)......
HTH。
答案 1 :(得分: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()
重置为零。