using System; using System.Diagnostics; using NAudio.Dsp; using NAudio.Wave; namespace NAudio.Extras { /// /// Demo sample provider that performs FFTs /// public class SampleAggregator : ISampleProvider { // volume public event EventHandler MaximumCalculated; private float maxValue; private float minValue; public int NotificationCount { get; set; } int count; // FFT public event EventHandler FftCalculated; public bool PerformFFT { get; set; } private readonly Complex[] fftBuffer; private readonly FftEventArgs fftArgs; private int fftPos; private readonly int fftLength; private readonly int m; private readonly ISampleProvider source; private readonly int channels; public SampleAggregator(ISampleProvider source, int fftLength = 1024) { channels = source.WaveFormat.Channels; if (!IsPowerOfTwo(fftLength)) { throw new ArgumentException("FFT Length must be a power of two"); } m = (int)Math.Log(fftLength, 2.0); this.fftLength = fftLength; fftBuffer = new Complex[fftLength]; fftArgs = new FftEventArgs(fftBuffer); this.source = source; } static bool IsPowerOfTwo(int x) { return (x & (x - 1)) == 0; } public void Reset() { count = 0; maxValue = minValue = 0; } private void Add(float value) { if (PerformFFT && FftCalculated != null) { fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftLength)); fftBuffer[fftPos].Y = 0; fftPos++; if (fftPos >= fftBuffer.Length) { fftPos = 0; // 1024 = 2^10 FastFourierTransform.FFT(true, m, fftBuffer); FftCalculated(this, fftArgs); } } maxValue = Math.Max(maxValue, value); minValue = Math.Min(minValue, value); count++; if (count >= NotificationCount && NotificationCount > 0) { MaximumCalculated?.Invoke(this, new MaxSampleEventArgs(minValue, maxValue)); Reset(); } } public WaveFormat WaveFormat => source.WaveFormat; public int Read(float[] buffer, int offset, int count) { var samplesRead = source.Read(buffer, offset, count); for (int n = 0; n < samplesRead; n+=channels) { Add(buffer[n+offset]); } return samplesRead; } } public class MaxSampleEventArgs : EventArgs { [DebuggerStepThrough] public MaxSampleEventArgs(float minValue, float maxValue) { MaxSample = maxValue; MinSample = minValue; } public float MaxSample { get; private set; } public float MinSample { get; private set; } } public class FftEventArgs : EventArgs { [DebuggerStepThrough] public FftEventArgs(Complex[] result) { Result = result; } public Complex[] Result { get; private set; } } }