为啥我的 FFT 提供的可视化工具输出与 Windows Media Player 不同?
Posted
技术标签:
【中文标题】为啥我的 FFT 提供的可视化工具输出与 Windows Media Player 不同?【英文标题】:Why does my FFT gives a different visualizer output than Windows Media Player?为什么我的 FFT 提供的可视化工具输出与 Windows Media Player 不同? 【发布时间】:2011-10-26 16:30:16 【问题描述】:我正在尝试使用 Visualizer 类在 android 中实现音频频谱分析仪。
我在OnDataCaptureListener()
事件的onFftDataCapture()
方法中获取FFT 数据,并使用drawLines()
在画布上绘制。
但频谱显示不正确。我只能看到图表左侧的变化。但是在 Window Media Player 中,同一首歌曲的输出是不同的。我错过了什么?
任何人都可以通过示例或链接帮助我吗?
代码
mVisualizer.setDataCaptureListener(
new Visualizer.OnDataCaptureListener()
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] bytes, int samplingRate)
public void onFftDataCapture(Visualizer visualizer,
byte[] bytes, int samplingRate)
mVisualizerView.updateVisualizer(bytes, samplingRate);
, Visualizer.getMaxCaptureRate() / 2, false, true);
onPaint()
for (int i = 0; i < mBytes.length / 2; i++)
mPoints[i * 4] = i * 8;
mPoints[i * 4 + 1] = 0;
mPoints[i * 4 + 2] = i * 8;
byte rfk = mBytes[2 * i];
byte ifk = mBytes[2 * i + 1];
magnitude = (float) (rfk * rfk + ifk * ifk);
int dbValue = (int) (10 * Math.log10(magnitude));
mPoints[i * 4 + 3] = (float) (dbValue * 7);
canvas.drawLines(mPoints, mForePaint);
其中mVisualizer
是Visualizer 类对象,mBytes
是从onFftDataCapture
事件获得的FFT 数据。
您可以阅读更多关于事件here返回的FFT数据。
这是我得到的值 onFftDataCapture()
:
[90, -1, -27, 102, 13, -18, 40, 33, -7, 16, -23, -23, -2, -8, -11, -9, -8, -33, -29, 44, 4, -9, -15, -1, -2, -17, -7, 1, 1, 0, 3, -11, -5, 10, -24, -6, -23, 1, -9, -21, -2, 4, 9, -10, -14, -5, -16, 8, 6, -16, 14, 3, 7, 15, 10, -2, -15, -14, -5, 10, 8, 23, -1, -16, -2, -6, 4, 9, -1, 0, 0, 9, 1, 4, -2, 6, -6, -6, 8, -4, 6, 6, -4, -5, -5, -2, 3, 0, -1, 0, -7, 0, 2, 1, 0, 1, -1, 0, -1, 1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -1]
任何想法,链接都会有所帮助。
@Chris Stratton 更新
现在我正在播放square wave at 1000 Hz 文件并截屏。你现在建议什么?
在@ruhalde 建议后更新
现在我正在播放Frequency sweep (20-20000 Hz) 文件,该文件生成了以下输出。
【问题讨论】:
每次重绘光谱之前,您是否都在清理画布?我只是(疯狂地)猜测碎片是以前的抽奖留下的...... 我在updateVisualizer()
方法中调用invalidate()
。它正在执行这项任务。
我认为您的 dB 和幅度公式不正确。第一幅值是通过乘以 SQR(2) 来计算的。同样以 dB 为单位,您需要除以一个限制,因为 dB 始终是与某事相关的度量。你没有按你的极限潜水,所以你的极限是 1 dB,这就是你的图表如此奇怪的原因。在这里查看公式zone.ni.com/devzone/cda/tut/p/id/4278
您不想快速扫描,因为要调试 FFT 分析仪,您希望它查看仅存在一个频率的输入。如果该频率在操作过程中发生变化,您将获得更复杂的结果,从而更难理解问题。 - 如果您必须使用文件而不是实时生成器,那么十个文件可能会更好,每个文件都有一个频率。此外,这个最新的图表根本不是一个有效的输出——也许你的屏幕截图在两个不同的绘图之间重新绘制过程中捕捉到了一些东西,显示了两个不同频率的扫描。
【参考方案1】:
通过在 windows 参考和正在开发的 android 应用程序上播放已知幅度的正弦曲线,准确地弄清楚行为与预期有何不同(希望这会导致理解原因)可能很有用。一次测试一个合成频率,并查看其在每个屏幕上绘制的位置、幅度和特异性以及表观幅度。
例如,您可能会发现覆盖频率范围内的差异,或者可能有一个版本将频率绘制在对数轴(十进制或八度音阶)而不是线性轴上。
如果您的数据源是麦克风,您的输入电路或设置也可能会出现衰减。
链接的文档没有说明正在使用什么窗口功能。此外,通过原始 FFT 输出,您可以将能量分布在相邻的 bin 之间,因此它可以产生更一致的结果,将每个点显示为两个或三个相邻点的平均值。
【讨论】:
供您参考,我需要媒体播放器的频谱,我会尝试“已知幅度正弦曲线”的建议。 我建议不要使用方波。你知道方波的频谱是什么样子的吗?也就是说,你可以看到一些有趣的事情——第三个峰值有我提到的相邻 bin 之间的能量分配问题。看起来你有一个高于 15 KHZ 的合理响应,然后可能来自某处的过滤器的一些滚降。 10 KHz 左右的“洞”很有趣。建议您通过设置一些可以调整正弦波频率的东西来更详细地探索这一点,这样在输入幅度恒定时您只会有一个频率。 我现在看到您正在使用 ogg 文件 - 不要那样做。尽管该文件在通过大胆解码和绘制时似乎具有不错的频谱,但您使用的解码器很可能是高频滚降和本底噪声中的那个洞的来源。要评估您的 FFT 和显示实现,不仅应该使用正弦波而不是方波进行测试,还应该使用线性 PCM 样本进行测试 - 如果您必须使用声音文件而不是原始数据,它们应该是 .wav 文件。【参考方案2】:我会在你的代码中看到一些缺陷,主要在这里>>
Visualizer.getMaxCaptureRate() / 2
不需要使用最大捕获率/2,只需在每秒 10 到 30 次之间设置一个值(根据文档,毫赫兹,但在 10000 到 30000 之间),这对于不闪烁和不闪烁就足够了对 Visualizer 内部的资源施加太大压力。此外,仅绘制 20 到 20Khz 之间的幅度,即可听频谱,在您的代码中,您正在绘制 0 和捕获率 /2 之间的每个频率,这是最大速率 /2,谁知道哪个频率更高。 ..
除此之外,您还需要一个纯正弦波,从 0 到 20Khz 不断扫描以查看它的外观,如果它是未经压缩的 RAW 文件会更好。我不会使用任何 OGG、MP3 或 PCM 文件,我会尝试未压缩的 WAV,也不会使用由于和声而产生大量以米为单位的尖峰的方波。
从here if you want 获取扫描文件 您是否尝试过运行另一个线程,轮询 getFft() 而不是使用 OnDataCaptureListener 进行轮询?我将在 Runnable 中尝试这种方法,使用 runOnUtiThread() 方法更新 UI。
【讨论】:
在整个范围内测试单频输入可能是调试的关键,但自动扫描可能会使分析变得困难,除非扫描速度足够慢以能够理解所看到的内容每个频率。然后需要使用稳定的输入来测试有问题的案例。以上是关于为啥我的 FFT 提供的可视化工具输出与 Windows Media Player 不同?的主要内容,如果未能解决你的问题,请参考以下文章
C# 应用程序:来自音频输出的示例音频 -> FFT 算法 -> 可视化