Exemple #1
0
 public InverseSTFT(IAudioWriterStream stream, int windowSize, int hopSize, int fftSize, WindowType windowType, float windowNormalizationFactor)
     : base(stream, windowSize, hopSize)
 {
     if (fftSize < windowSize)
     {
         throw new ArgumentOutOfRangeException("fftSize must be >= windowSize");
     }
     frameBuffer     = new float[fftSize];
     fft             = new PFFFT.PFFFT(fftSize, PFFFT.Transform.Real);
     synthesisWindow = WindowUtil.GetFunction(windowType, windowSize, windowNormalizationFactor);
 }
Exemple #2
0
 /// <summary>
 /// Initializes a new STFT for the specified stream with the specified window, hop, and FFT size.
 /// An FFT size larger than the window size can be used to increase frequency resolution. Window will be right-padded with zeros for FFT.
 /// </summary>
 /// <param name="stream">the stream to read the audio data to process from</param>
 /// <param name="windowSize">the window size in the dimension of samples</param>
 /// <param name="hopSize">the hop size in the dimension of samples</param>
 /// <param name="fftSize">the FFT size, must be >= windowSize</param>
 /// <param name="windowType">the type of the window function to apply</param>
 /// <param name="outputFormat">format of the output data, e.g. raw FFT complex numbers or dB spectrum</param>
 public STFT(IAudioStream stream, int windowSize, int hopSize, int fftSize, WindowType windowType, OutputFormat outputFormat)
     : base(stream, windowSize, hopSize, windowType)
 {
     if (fftSize < windowSize)
     {
         throw new ArgumentOutOfRangeException("fftSize must be >= windowSize");
     }
     frameBuffer = new float[fftSize];
     fftBuffer   = new float[fftSize];
     Array.Clear(frameBuffer, 0, frameBuffer.Length);     // init with zeros (assure zero padding)
     fft = new PFFFT.PFFFT(fftSize, PFFFT.Transform.Real);
     this.outputFormat = outputFormat;
 }
Exemple #3
0
        public static double FrequencyDistribution(byte[] x, byte[] y)
        {
            if (x.Length != y.Length)
            {
                throw new ArgumentException("interval lengths do not match");
            }

            int samples = x.Length / 4;

            float[] xF = new float[samples];
            float[] yF = new float[samples];

            Buffer.BlockCopy(x, 0, xF, 0, x.Length);
            Buffer.BlockCopy(y, 0, yF, 0, y.Length);

            int fftSize = 2048; // max FFT size

            // if there are less samples to analyze, find a fitting FFT size
            while (fftSize > samples)
            {
                fftSize /= 2;
            }
            int hopSize = fftSize / 8;

            if (fftSize < 64)
            {
                throw new Exception("FFT might be too small to get a meaningful result");
            }

            double[] xSum   = new double[fftSize / 2];
            double[] ySum   = new double[fftSize / 2];
            float[]  buffer = new float[fftSize];

            if (windowFunction == null || windowFunction.Size != fftSize)
            {
                windowFunction = WindowUtil.GetFunction(WindowType.Hann, fftSize);
            }

            var fft = new PFFFT.PFFFT(fftSize, PFFFT.Transform.Real);

            int blocks = (samples - fftSize) / hopSize;

            for (int block = 0; block < blocks; block++)
            {
                Array.Copy(xF, block * hopSize, buffer, 0, buffer.Length);
                FrequencyDistributionBlockProcess(buffer, xSum, fft);

                Array.Copy(yF, block * hopSize, buffer, 0, buffer.Length);
                FrequencyDistributionBlockProcess(buffer, ySum, fft);
            }

            fft.Dispose();

            // remove DC offset
            xSum[0] = 0;
            ySum[0] = 0;

            double xScalarSum = xSum.Sum();
            double yScalarSum = ySum.Sum();

            double result = 0;

            for (int i = 0; i < fftSize / 2; i++)
            {
                result += Math.Abs(xSum[i] / xScalarSum - ySum[i] / yScalarSum);
            }

            return(1 - result);
        }
Exemple #4
0
 private static void FrequencyDistributionBlockProcess(float[] buffer, double[] target, PFFFT.PFFFT fft)
 {
     windowFunction.Apply(buffer);
     fft.Forward(buffer);
     for (int i = 0; i < buffer.Length; i += 2)
     {
         buffer[i / 2] = FFTUtil.CalculateMagnitude(buffer[i], buffer[i + 1]) / buffer.Length * 2;
     }
     for (int i = 0; i < target.Length; i++)
     {
         target[i] += buffer[i];
     }
 }
Exemple #5
0
        private void Generate(FFTLibrary fftLib)
        {
            // FFT resources:
            // http://www.mathworks.de/support/tech-notes/1700/1702.html
            // http://stackoverflow.com/questions/6627288/audio-spectrum-analysis-using-fft-algorithm-in-java
            // http://stackoverflow.com/questions/1270018/explain-the-fft-to-me
            // http://stackoverflow.com/questions/6666807/how-to-scale-fft-output-of-wave-file

            /*
             * FFT max value test:
             * 16Hz, 1024 samplerate, 512 samples, rectangle window
             * -> input min/max: -1/1
             * -> FFT max: 256
             * -> FFT result max: ~1
             * -> FFT dB result max: ~1
             *
             * source: "Windowing Functions Improve FFT Results, Part I"
             * => kann zum Normalisieren für Fensterfunktionen verwendet werden
             */

            float frequency       = float.Parse(frequencyTextBox.Text);
            int   ws              = (int)windowSize.Value;
            float frequencyFactor = ws / frequency;
            int   sampleRate      = int.Parse(sampleRateTextBox.Text);

            SineGeneratorStream sine = new SineGeneratorStream(sampleRate, frequency, new TimeSpan(0, 0, 1));

            float[] input = new float[ws];
            sine.Read(input, 0, ws);

            //// add second frequency
            //SineGeneratorStream sine2 = new SineGeneratorStream(44100, 700, new TimeSpan(0, 0, 1));
            //float[] input2 = new float[ws];
            //sine2.Read(input2, 0, ws);
            //for (int x = 0; x < input.Length; x++) {
            //    input[x] += input2[x];
            //    input[x] /= 2;
            //}

            //// add dc offset
            //for (int x = 0; x < input.Length; x++) {
            //    input[x] += 0.5f;
            //}

            inputGraph.Values = input;

            WindowFunction wf = WindowUtil.GetFunction((WindowType)windowTypes.SelectedValue, ws);

            float[] window = (float[])input.Clone();
            wf.Apply(window);

            input2Graph.Values = window;

            float[] fftIO = (float[])window.Clone();

            if (fftLib == FFTLibrary.ExocortexDSP)
            {
                // This function call indirection is needed to allow this method execute even when the
                // Exocortex FFT assembly is missing.
                ApplyExocortexDSP(fftIO);
            }
            else if (fftLib == FFTLibrary.FFTW)
            {
                FFTW.FFTW fftw = new FFTW.FFTW(fftIO.Length);
                fftw.Execute(fftIO);
            }
            else if (fftLib == FFTLibrary.PFFFT)
            {
                PFFFT.PFFFT pffft = new PFFFT.PFFFT(fftIO.Length, PFFFT.Transform.Real);
                pffft.Forward(fftIO, fftIO);
            }

            //// convert real input to complex input with im part set to zero
            //float[] fftIO = new float[ws * 2];
            //int i = 0;
            //for (int j = 0; j < window.Length; j++) {
            //    fftIO[i] = window[j];
            //    i += 2;
            //}
            //Fourier.FFT(fftIO, fftIO.Length / 2, FourierDirection.Forward);

            fftOutputGraph.Values = fftIO;


            float[] fftResult = new float[ws / 2];
            //FFTUtil.Results(fftIO, fftResult);

            // transform complex output to magnitudes
            float sum = 0;
            int   y   = 0;

            for (int x = 0; x < fftIO.Length; x += 2)   //  / 2
            {
                fftResult[y] = FFTUtil.CalculateMagnitude(fftIO[x], fftIO[x + 1]) / ws * 2;
                sum         += fftResult[y++];
            }
            //FFTUtil.Results(fftIO, fftResult);

            //// adjust values for the sum to become 1
            //float sum2 = 0;
            //for (int x = 0; x < fftResult.Length; x++) {
            //    fftResult[x] /= sum;
            //    sum2 += fftResult[x];
            //}
            //Debug.WriteLine("sum / sum2: {0} / {1}", sum, sum2);

            fftNormalizedOutputGraph.Values = fftResult;

            // convert magnitudes to decibel
            float[] fftResultdB = new float[fftResult.Length];
            //for (int x = 0; x < fftResult.Length; x++) {
            //    fftResultdB[x] = (float)VolumeUtil.LinearToDecibel(fftResult[x]);
            //}
            FFTUtil.Results(fftIO, fftResultdB);
            fftdBOutputGraph.Values = fftResultdB;

            summary.Text = String.Format(
                "input min/max: {0}/{1} -> window min/max: {2}/{3} -> fft min/max: {4}/{5} -> result min/max/bins/sum: {6}/{7}/{8}/{9} -> dB min/max: {10:0.000000}/{11:0.000000}",
                input.Min(), input.Max(),
                window.Min(), window.Max(),
                fftIO.Min(), fftIO.Max(),
                fftResult.Min(), fftResult.Max(), fftResult.Length, sum,
                fftResultdB.Min(), fftResultdB.Max());
        }