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?
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.