Search code examples
wpfnaudio

GetFFTData method in NAudio


I`m working on the Spectrum analyzer for NAudio. My question is - how can I get FFTData like in Bass.net with method

 public static int BASS_ChannelGetData(int handle, float[] buffer, int length);

I tried to use

 public void GetFFTResults(float[] fftBuffer)
    {
        Complex[] channelDataClone = new Complex[bufferSize];
        channelData.CopyTo(channelDataClone, 0);
        FastFourierTransform.FFT(true, binaryExponentitation, channelDataClone);
        for (int i = 0; i < channelDataClone.Length / 2; i++)
        {
            fftBuffer[i] = (float)Math.Sqrt(channelDataClone[i].X * channelDataClone[i].X + channelDataClone[i].Y * channelDataClone[i].Y);
        }
    }

Is this only one way to GetFFTData in NAudio?


Solution

  • Mark has written some code in the NAudio WPF demo folder that shows how the FFT classes works in NAudio. There is a handy class which encapsulates the whole FFT process and is remarkably simple to use.

    The SampleAggregator class (which should totally be part of the main library Mark!) is an ISampleProvider that observes waveform data passing through it and fires events each time it has observed enough data to fill and process the FFT buffer or when it has processed a block (of whatever length) for min/max values.

    For usage, simply put an instance of it inline in your audio stream:

    // open the source file
    var waveStream = new AudioFileReader(sourceFilename);
    // create an aggregator 
    var aggregator = new SampleAggregator(waveStream);
    aggregator.PerformFFT = true;
    aggregator.FftCalculated += OnFftCalculated;
    // start wave playback
    waveOut.Init(aggregator)
    

    The OnFftCalculated will be called once for every 1024 samples read by the waveOut device. You can adjust this by passing a different power-of-2 FFT size to the constructor as a second parameter.

    SampleAggregator will give you the FFT data for the first channel only and will not do overlapped FFTs so you will get only discrete blocks. At 44.1 kHz sample rate the block size is only ~2.3ms wide, so probably not an issue. 8kHz is ugly enough that dropping the FFT buffer size down a bit probably won't hurt much if at all.

    The data flow for SampleAggregator is keyed from the Read method, and events are raised in the same thread context as the WaveOut so anything you do in response to the events should be fairly quick or you're likely to get choppy audio.