1

I am trying to create an audio visualizer in the Unity game engine using C#.

I am also using the FMOD plugin which has functions for retrieving the audio spectrum of a playing sound (aka the volume of a sound across a range of frequencies).

FMOD returns this data as a struct containing a jagged array, with the first array being the audio channel (0 = left, 1 = right), and the second array being the volumes for each frequency range, being a float value between 0 and 1.

I need to copy the values in these arrays into my own arrays, for the purposes of altering and displaying the data. I am currently using a for-loop to iterate through the array and assign the values from the left and right channels to new arrays, as well as another array that finds the average volume:

private int SAMPLE_SIZE = 512;
private float[] spectrumLeft;
private float[] spectrumRight;
public float[] spectrumTotal;

void Start () {
    spectrumLeft = new float[SAMPLE_SIZE];
    spectrumRight = new float[SAMPLE_SIZE];
    spectrumTotal = new float[SAMPLE_SIZE];
}

void Update () {
    System.IntPtr data;
    uint length;
    result = spectrumFilter.getParameterData ((int)FMOD.DSP_FFT.SPECTRUMDATA, out data, out length);
    FMOD.DSP_PARAMETER_FFT spectrumBuffer = new FMOD.DSP_PARAMETER_FFT ();
    spectrumBuffer = (FMOD.DSP_PARAMETER_FFT) Marshal.PtrToStructure(data,typeof (FMOD.DSP_PARAMETER_FFT));

    for (int i = 0; i < SAMPLE_SIZE; i++) {
        spectrumLeft[i] = spectrumBuffer.spectrum[0][i];
        spectrumRight[i] = spectrumBuffer.spectrum[1][i];
        spectrumTotal[i] = (spectrumLeft[i] + spectrumRight[i]) / 2f;
    }
}

THE PROBLEM: The code running in the for-loop above is incredibly slow (It maxes out my CPU core and causes the program to run slowly, when I comment out the contents of the loop the CPU usage is below 1%).

Since FMOD returns the data as a struct in this format I cannot change how I retrieve the data.

Is there a better/faster way of retrieving values from a struct?

Note that I am relatively new to C# and I may be missing something obvious

anothershrubery
  • 20,461
  • 14
  • 53
  • 98
SJTho
  • 11
  • 3
  • 1
    Without [a good, _minimal_, _complete_ code example](http://stackoverflow.com/help/mcve) that reliably reproduces the problem, it would be difficult if not impossible to know where your bottleneck is for sure. But the first two things I'd try: use [`Buffer.BlockCopy()`](https://msdn.microsoft.com/en-us/library/vstudio/system.buffer.blockcopy(v=vs.110).aspx) to copy data to each of the `spectrumLeft` and `spectrumRight` arrays, and see if just removing the `spectrumTotal` makes a significant difference. – Peter Duniho Apr 30 '15 at 06:41
  • http://stackoverflow.com/a/5099642/312725 this may help you with copying the array. Essentially, it's the same as what @PeterDuniho said, but explained in detail. – Max Yankov Apr 30 '15 at 06:49
  • @PeterDuniho I'm fairly sure this is the bottleneck, I've tried commenting out each of the functions in the for loop and even replaced them with other functions and nothing causes even a noticeable hit in performance. Also for whatever reason Unity does not appear to have the Buffer class, so I cannot use Buffer.BlockCopy() – SJTho Apr 30 '15 at 07:54

1 Answers1

0

Ok, very simple fix I overlooked:

private int SAMPLE_SIZE = 512;
private float[][] spectrum;
public float[] spectrumTotal;

void Start () {
    spectrum = new float[2][];
    spectrum[0] = new float[SAMPLE_SIZE];
    spectrum[1] = new float[SAMPLE_SIZE];
    spectrumTotal = new float[SAMPLE_SIZE];
}

void Update () {
    System.IntPtr data;
    uint length;
    result = spectrumFilter.getParameterData ((int)FMOD.DSP_FFT.SPECTRUMDATA, out data, out length);
    FMOD.DSP_PARAMETER_FFT spectrumBuffer = new FMOD.DSP_PARAMETER_FFT ();
    spectrumBuffer = (FMOD.DSP_PARAMETER_FFT) Marshal.PtrToStructure(data,typeof (FMOD.DSP_PARAMETER_FFT));

    spectrum = spectrumBuffer.spectrum;

    for (int i = 0; i < SAMPLE_SIZE; i++) {
        spectrumTotal[i] = (spectrum[0][i] + spectrum[1][i]) / 2f;
    }
}

Rather than iterating through the entire array and assigning each value one by one, I simply declared my own jagged array with the same size as the one in the struct and copied it all over in one go. Then I can loop through them and find the average volume.

I am however still interested in why it takes so much longer to get a value from an array in a struct, compared to just another local array. Will do some more research.

Silly mistake now that I see it but thanks, was amazed at how quickly people posted helpful responses.

SJTho
  • 11
  • 3