安卓可视化器FFT数据取决于音量

3
我正在为一个使用Android Visualizer类的Unity应用程序编写插件。我正在使用getFft()函数和提供的代码来获取FFT幅度。返回值取决于音量-音量越高,返回值就越高,音量越低,返回值就越低。

这是我的构造函数,在其中初始化Visualizer:
private PluginClass() {
    errors = new int[2];
    int size = Visualizer.getCaptureSizeRange()[1];

    // Equalizer
    Equalizer mEqualizer = new Equalizer(0, 0);

    // Visualizer
    this.visualizer = new Visualizer(0);
    this.visualizer.setEnabled(false);
    mEqualizer.setEnabled(true);
    this.visualizer.setCaptureSize(size);
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
       this.visualizer.setScalingMode(SCALING_MODE_NORMALIZED);
       this.visualizer.setMeasurementMode(MEASUREMENT_MODE_PEAK_RMS);
    }
    this.visualizer.setEnabled(true);

    this.waveFormData = new byte[size];
    this.fftData = new byte[size];
}

我正在设置均衡器(在创建 Visualizer 实例之前、之后、禁用之前和之后以及其他时间都调用了 setEnabled)。

缩放模式被设置为归一化,当我调用 getScalingMode() 时,我可以确认它确实设置为 SCALING_MODE_NORMALIZED

有没有人有任何想法是什么原因呢?在此问题的另一个重复问题中,没有解释,唯一的答案是使用 setVolumeControlStream(AudioManager.STREAM_MUSIC);。我已经尝试过了,但它似乎没有起作用,而我也不知道为什么会起作用。

在这之前,已经有其他人提出了同样的问题,但他们已经放弃了,未提供代码并等待答案,所以我要重新提问。同时,我也会为此问题添加奖励。

在 VR 模式下运行应用程序,以防这是与 VR 和 Android Java 和 Unity 不兼容的某些鲜为人知的 bug。

谢谢!

编辑 这是我用来生成 FFT 幅度的代码:

public float[] getFftMagnitudes() {
    this.errors[0] = this.visualizer.getFft(this.fftData);
    int n = this.fftData.length;
    float[] magnitudes = new float[n / 2 + 1];
    magnitudes[0] = (float)Math.abs(this.fftData[0]);      // DC
    magnitudes[n / 2] = (float)Math.abs(this.fftData[1]);  // Nyquist
    for (int k = 1; k < n / 2; k++) {
        int i = k * 2;
        magnitudes[k] = (float)Math.hypot(this.fftData[i], this.fftData[i + 1]);
    }
    return magnitudes;
}

只是确认一下:您的代码所有运行中,size都是相同的吗? - Ichneumwn
@Ichneumwn,虽然我尝试了不同的2次幂,但都没有成功。 - Big Money
重新审视这个问题,实际上的问题可能是 getFft() 如何将其结果适配到8位整数中。它必须进行一些数据相关的缩放(不同于之前讨论的 1/N 和音频音量归一化)... 我可以想象它进行的操作类似于按比例缩放 127/max(FFT浮点幅度值)). 猜测并不能帮助你 :( - Ichneumwn
1个回答

2

一些FFT实现(例如FFTW)不会对结果进行归一化。因此,如果您有一个数组x,将其转换为傅里叶空间x',然后再将其转回来,您不会得到原始结果。在FFTW的情况下,您必须除以数组的长度。这可能有点牵强,但您的问题听起来非常熟悉。

最初的回答:

某些FFT实现(例如FFTW)不会对其结果进行归一化。因此,如果您有一个名为x的数组,将其转换为傅里叶空间x',然后再将其转换回来,您将无法获得原始结果。对于FFTW,您需要将结果除以数组的长度。虽然这可能与您的问题没有直接关系,但它听起来非常相似。


这就是为什么我问关于 size 的原因 - 如果它是相同的,那么FFT的归一化(或缺乏归一化)就不重要了。 - Ichneumwn
另外,你是否检查了缩放模式规范化是否也适用于FFT函数。可能规范化是针对其他量而言的。 - MPIchael
根据文档,它会标准化音频音量。这也是 OP 所询问的:尽管音频音量已经被标准化,但他仍然得到不同的结果。除非音频序列的“大小”(长度)与音频音量有所变化,否则 FFT 的标准化不可能成为问题。 - Ichneumwn
傅里叶变换的输入是否可能未经过归一化,但如果您从类中请求音频输入,则会提供已归一化的音频信号? - MPIchael
@MPIchael,您是说要将FFT幅度数组中的每个值除以数组的长度吗?编辑:我刚试了一下,似乎不起作用:( - Big Money

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接