3

I'm writing a plugin for a Unity application that uses the Android Visualizer class. I'm using the getFft() function and the code provided there to get the FFT magnitudes. The values returned are dependent on volume - much higher values with higher volume, and much lower values with lower volume.

Here is my constructor where I initialize the 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];
}

I'm setting the equalizer (I've called setEnabled before the Visualizer was created, after it was created but before it was disabled, after it was disabled, pretty much all over).

The scaling mode is set to be normalized, and when I call getScalingMode() I can confirm that it is indeed set to SCALING_MODE_NORMALIZED.

Does anyone have any ideas as to why this is? In the other duplicate of this question, with no explanation, the one answer says to use setVolumeControlStream(AudioManager.STREAM_MUSIC);. I tried this to no avail, but I don't see why it would work anyways.

The OPs have abandoned their questions who have asked this before, with pending questions by answerers asked, and no code provided, so I had to open this one. This way, I can also add a bounty to the question.

I am running the app in VR mode in case this is some obscure bug with VR and Android Java and Unity not playing nicely together.

Thanks!

Edit Here is the code I use to actually generate the FFT Magnitudes:

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;
}
Big Money
  • 9,139
  • 6
  • 26
  • 37
  • Just checking: is `size` the same for all your runs of the code? – Ichneumwn Apr 24 '19 at 07:44
  • @Ichneumwn it is, though I have tried with different powers of two to no avail – Big Money Apr 24 '19 at 18:53
  • Looking at this again, the real question might be how `getFft()` fits its results in 8-bit integers. It must do some data-dependent scaling (different from the 1/N that was discussed before and different from the audio volume normalisation)... I could imagine it doing something like scaling by 127/max(magnitude of FFT in float)). Guess work won't help you though :( – Ichneumwn Apr 25 '19 at 21:21

1 Answers1

2

some FFT implementations (e.g. FFTW) do not norm their results. So if you have an array x, transform it to fourier space x' and then back you do not end up with the original result. In the case of FFTW you have to devide by the length of the array. It is a long shot, but your problem sounds eerily familiar to that.

MPIchael
  • 176
  • 7
  • That's why I asked about `size` - if it is the same, then the normalisation (or lack of it) by the FFT does not matter – Ichneumwn Apr 24 '19 at 14:22
  • Also: Have you checked if the Scaling Mode Normalized applies also to the FFT function. It might be that the normalization is meant for some other quantity. – MPIchael Apr 24 '19 at 14:46
  • According to the docs, it normalises the audio volume. And that is what the OP seems to be asking: despite the normalisation of the audio volume, he is getting different results. The normalisation of the FFT cannot be an issue, unless the `size` (length) of the audio sequence happens to vary with the audio volume. – Ichneumwn Apr 24 '19 at 15:53
  • is it possible that the input of the fourier transform is not normalized, but if you request the audio input from the class it will deliver the normalized audio signal? – MPIchael Apr 25 '19 at 09:23
  • @MPIchael Are you saying to divide each value in the FFT magnitudes array by the length of the array? Edit: Just tried this and it does not seem to work :( – Big Money Apr 25 '19 at 18:50