2015-02-08 103 views
1

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

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

这就是我想在我OpenGL应用程序来实现:

enter image description here

因此,在每一帧,有输入数据的一部分。在for循环(因此多次通过)中,将消耗当前数据的窗口并对其执行FFT分析。对于for循环的下一次迭代,窗口将通过数据等提前“跳跃大小”,直到达到数据的末尾。

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

现在你可以说,选择window-size/hop-size的方式永远不会发生,但这是不可能的,因为这些参数应该在我的项目中留给用户配置。

对于面向C++ 11的这种处理的建议也非常受欢迎!

谢谢!

+0

我不明白这个字眼:*“只要N个样本的数量完成,当前缓冲区的处理完成,下一个输入缓冲区的第一窗块将不相关的差距与上次窗口块到k来自上一个缓冲区的数据“* - 也许您可以为我们绘制该部分的一些ASCII图表? – 2015-02-09 05:17:38

+0

@JohnZwinck我收录了一张图片,希望能够展示我想要达到的目标。谢谢! – Sepehr 2015-02-09 19:39:21

回答

1

不知道我理解你的方案100%,但听起来像你可能想要使用循环缓冲区。没有“标准”循环缓冲区,但是there's one in Boost

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

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

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

HTH。

+0

在libcinder中有一个[RingBuffer类](https://github.com/cinder/Cinder/blob/master/include/cinder/audio/dsp/RingBuffer.h)用于这个目的(迎合音频处理)。 – 2015-12-11 04:34:17

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()重置为零。