コード例 #1
0
ファイル: Program.cs プロジェクト: xiaopinggai-webrtc/Aurio
        /// <summary>
        /// Simulates a realtime audio stream by generating a sine wave in realtime and ingesting it into the FIFO buffer.
        /// </summary>
        private static void StartSineWaveRealtimeGenerator(AudioProperties audioProperties, IAudioWriterStream targetStream)
        {
            // Create a stream that generates 1 second of a sine wave
            var sineWaveStream = new SineGeneratorStream(audioProperties.SampleRate, 440, new TimeSpan(0, 0, 1));

            // Store the sine wave in a buffer
            // We can concatenate this buffer over and over again to create an infinitely long sine wave
            var sineWaveBuffer = new byte[sineWaveStream.Length];
            var bytesRead      = sineWaveStream.Read(sineWaveBuffer, 0, sineWaveBuffer.Length);

            if (bytesRead < sineWaveBuffer.Length)
            {
                throw new Exception("incomplete buffer read");
            }

            Task.Factory.StartNew(() =>
            {
                // Each realtime second, write the 1-second sine wave to the target stream to
                // simulate an infinitely long realtime sine wave stream.
                //
                // For low-latency processing use-cases, writes would ideally be shorter and happen
                // more frequently to keep the delay between input and output of the FIFO stream
                // as low as possible.
                while (true)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("Writing 1 second into buffer");
                    targetStream.Write(sineWaveBuffer, 0, sineWaveBuffer.Length);
                    _dataGenerated += sineWaveBuffer.Length;
                }
            });
        }
コード例 #2
0
        public void TransformForwardAndBackward()
        {
            int size     = 4096;
            var pffft    = new PFFFT(size, Transform.Real);
            var dataIn   = new float[size];
            var dataOut  = new float[size];
            var dataBack = new float[size];

            var generator = new SineGeneratorStream(4096, 100, TimeSpan.FromSeconds(1));

            generator.Read(dataIn, 0, size);

            pffft.Forward(dataIn, dataOut);
            pffft.Backward(dataOut, dataBack);

            CollectionAssert.AreEqual(dataIn, dataBack, new FFTComparer());
        }
コード例 #3
0
        /// <summary>
        /// Calculates a normalization offset for the current window function. Every window function leads to
        /// a different FFT result peak value, and since the peak value of each windowed FFT means 0dB, this
        /// offset can be used to adjust the calculated dB values.
        /// </summary>
        private void CalculateWindowFunctionNormalizationOffset()
        {
            if (windowFunction == null)
            {
                windowFunctionNormalizationDecibelOffset = 0;
            }
            else
            {
                SineGeneratorStream sine   = new SineGeneratorStream(1024, 16, new TimeSpan(0, 0, 1));
                float[]             input  = new float[WindowSize];
                float[]             output = new float[input.Length / 2];
                WindowFunction      wf     = WindowUtil.GetFunction(windowFunction.Type, input.Length);

                sine.Read(input, 0, input.Length);
                wf.Apply(input);
                fft.Forward(input);
                int   maxIndex = FFTUtil.Results(input, output);
                float maxValue = output[maxIndex];
                windowFunctionNormalizationDecibelOffset = 1f - maxValue;
            }
        }
コード例 #4
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());
        }