예제 #1
0
        //-----------------------------------------------------------------------------
        // GetCoarseAperiodicity() calculates the aperiodicity in multiples of 3 kHz.
        // The upper limit is given based on the sampling frequency.
        //-----------------------------------------------------------------------------
        private void GetCoarseAperiodicity(double[] staticGroupDelay, int fs, int fftSize, int numberOfAperiodicities, double[] window, ForwardRealFFT forwardRealFFT, SubSequence <double> coarseAperiodicity)
        {
            var boundary         = MatlabFunctions.MatlabRound(fftSize * 8.0 / window.Length);
            var halfWindowLength = window.Length / 2;

            Array.Clear(forwardRealFFT.Waveform, 0, fftSize);

            var powerSpectrum = new double[fftSize / 2 + 1];

            for (var i = 0; i < numberOfAperiodicities; i++)
            {
                var center = (int)(FrequencyInterval * (i + 1) * fftSize / fs);
                for (int j = 0, limit = halfWindowLength * 2; j <= limit; j++)
                {
                    forwardRealFFT.Waveform[j] = staticGroupDelay[center - halfWindowLength + j] * window[j];
                }
                FFT.Execute(forwardRealFFT.ForwardFFT);

                var spectrum = forwardRealFFT.Spectrum;
                for (int j = 0, limit = fftSize / 2; j <= limit; j++)
                {
                    powerSpectrum[j] = spectrum[j].Real * spectrum[j].Real + spectrum[j].Imaginary * spectrum[j].Imaginary;
                }

                Array.Sort(powerSpectrum);
                for (int j = 1, limit = fftSize / 2; j <= limit; j++)
                {
                    powerSpectrum[j] += powerSpectrum[j - 1];
                }

                coarseAperiodicity[i] = 10.0 * Math.Log10(powerSpectrum[fftSize / 2 - boundary - 1] / powerSpectrum[fftSize / 2]);
            }
        }
예제 #2
0
        //-----------------------------------------------------------------------------
        // SmoothingWithRecovery() carries out the spectral smoothing and spectral
        // recovery on the Cepstrum domain.
        //-----------------------------------------------------------------------------
        void SmoothingWithRecovery(double f0, int fs, ForwardRealFFT forwardRealFFT, InverseRealFFT inverseRealFFT, double[] spectralEnvelope)
        {
            var smoothingLifter    = new double[FFTSize];
            var compensationLifter = new double[FFTSize];

            smoothingLifter[0]    = 1;
            compensationLifter[0] = (1.0 - 2.0 * Q1) + 2.0 * Q1;
            for (int i = 1, limit = forwardRealFFT.FFTSize / 2; i <= limit; i++)
            {
                var quefrency = (double)i / fs;
                smoothingLifter[i]    = Math.Sin(Math.PI * f0 * quefrency) / (Math.PI * f0 * quefrency);
                compensationLifter[i] = (1.0 - 2.0 * Q1) + 2.0 * Q1 * Math.Cos(2.0 * Math.PI * quefrency * f0);
            }

            for (int i = 0, limit = FFTSize / 2; i <= limit; i++)
            {
                forwardRealFFT.Waveform[i] = Math.Log(forwardRealFFT.Waveform[i]);
            }
            for (int i = 1, limit = FFTSize / 2; i < limit; i++)
            {
                forwardRealFFT.Waveform[FFTSize - i] = forwardRealFFT.Waveform[i];
            }
            FFT.Execute(forwardRealFFT.ForwardFFT);

            for (int i = 0, limit = FFTSize / 2; i <= limit; i++)
            {
                inverseRealFFT.Spectrum[i] = new Complex(forwardRealFFT.Spectrum[i].Real * smoothingLifter[i] * compensationLifter[i] / FFTSize, 0.0);
            }
            FFT.Execute(inverseRealFFT.InverseFFT);

            for (int i = 0, limit = FFTSize / 2; i <= limit; i++)
            {
                spectralEnvelope[i] = Math.Exp(inverseRealFFT.Waveform[i]);
            }
        }
예제 #3
0
    private void ProcessFullSpectrum(
        SpectralFluxAnalyzer analyzer,
        ThreadSafeAudioClip clip,
        OnAudioClipProcessed callback)
    {
        var processedSamples = GetChannelsCombined(clip.Samples, clip.ChannelCount, clip.SampleCount);

        Debug.Log("Channels have been combined");

        var iterations = processedSamples.Length / _fftSampleSize;

        var fft = new FFT();

        fft.Initialize(_fftSampleSize);

        var chunk = new double[_fftSampleSize];

        for (var i = 0; i < iterations; ++i)
        {
            Array.Copy(processedSamples, i * _fftSampleSize, chunk, 0, _fftSampleSize);

            var windowCoefficients  = DSP.Window.Coefficients(DSP.Window.Type.Hamming, _fftSampleSize);
            var scaledSpectrumChunk = DSP.Math.Multiply(chunk, windowCoefficients);
            var scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefficients);

            var fftSpectrum       = fft.Execute(scaledSpectrumChunk);
            var scaledFftSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
            scaledFftSpectrum = DSP.Math.Multiply(scaledFftSpectrum, scaleFactor);

            var currentSongTime = GetTimeFromIndex(i, clip.Frequency) * _fftSampleSize;
            analyzer.AnalyzeSpectrum(Array.ConvertAll(scaledFftSpectrum, x => (float)x), currentSongTime);
        }

        callback(analyzer);
    }
예제 #4
0
        //-----------------------------------------------------------------------------
        // GetAperiodicResponse() calculates an aperiodic response.
        //-----------------------------------------------------------------------------
        void GetAperiodicResponse(int noiseSize, int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, ForwardRealFFT forwardRealFFT, InverseRealFFT inverseRealFFT, MinimumPhaseAnalysis minimumPhase, double[] aperiodicResponse)
        {
            GetNoiseSpectrum(noiseSize, fftSize, forwardRealFFT);

            var logSpectrum = minimumPhase.LogSpectrum;

            if (currentVUV != 0.0)
            {
                for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++)
                {
                    logSpectrum[i] = Math.Log(spectrum[i] * aperiodicRatio[i]) / 2.0;
                }
            }
            else
            {
                for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++)
                {
                    logSpectrum[i] = Math.Log(spectrum[i]) / 2.0;
                }
            }
            Common.GetMinimumPhaseSpectrum(minimumPhase);

            var minimumPhaseSpectrum = minimumPhase.MinimumPhaseSpectrum;

            Array.Copy(minimumPhaseSpectrum, 0, inverseRealFFT.Spectrum, 0, fftSize / 2 + 1);
            for (int i = 0, limit = fftSize / 2; i <= limit; i++)
            {
                var real      = minimumPhaseSpectrum[i].Real * forwardRealFFT.Spectrum[i].Real - minimumPhaseSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Imaginary;
                var imaginary = minimumPhaseSpectrum[i].Real * forwardRealFFT.Spectrum[i].Imaginary + minimumPhaseSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Real;

                inverseRealFFT.Spectrum[i] = new Complex(real, imaginary);
            }
            FFT.Execute(inverseRealFFT.InverseFFT);
            MatlabFunctions.FFTShift(inverseRealFFT.Waveform.SubSequence(0, fftSize), aperiodicResponse);
        }
예제 #5
0
        //-----------------------------------------------------------------------------
        // GetPeriodicResponse() calculates an aperiodic response.
        //-----------------------------------------------------------------------------
        void GetPeriodicResponse(int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, InverseRealFFT inverseRealFFT, MinimumPhaseAnalysis minimumPhase, double[] dcRemover, double fractionalTimeShift, int fs, double[] periodicResponse)
        {
            if (currentVUV <= 0.5 || aperiodicRatio[0] > 0.999)
            {
                Array.Clear(periodicResponse, 0, fftSize);
                return;
            }

            var logSpectrum = minimumPhase.LogSpectrum;

            for (int i = 0, limit = minimumPhase.FFTSize / 2; i <= limit; i++)
            {
                logSpectrum[i] = Math.Log(spectrum[i] * (1.0 - aperiodicRatio[i]) + SafeGuardMinimum) / 2.0;
            }
            Common.GetMinimumPhaseSpectrum(minimumPhase);
            Array.Copy(minimumPhase.MinimumPhaseSpectrum, 0, inverseRealFFT.Spectrum, 0, fftSize / 2 + 1);

            double coefficient = PI2 * fractionalTimeShift * fs / fftSize;

            GetSpectrumWithFractionalTimeShift(fftSize, coefficient, inverseRealFFT);

            FFT.Execute(inverseRealFFT.InverseFFT);
            MatlabFunctions.FFTShift(inverseRealFFT.Waveform.SubSequence(0, fftSize), periodicResponse);
            RemoveDCComponent(periodicResponse, fftSize, dcRemover, periodicResponse);
        }
예제 #6
0
        void GetCentroid(double[] x, int fs, double currentF0, int fftSize, double currentPosition, ForwardRealFFT forwardRealFFT, double[] centroid)
        {
            Array.Clear(forwardRealFFT.Waveform, 0, fftSize);
            GetWindowedWaveform(x, fs, currentF0, currentPosition, WindowType.Blackman, 4.0, forwardRealFFT.Waveform);

            var windowRange = MatlabFunctions.MatlabRound(2.0 * fs / currentF0) * 2;
            var power       = Math.Sqrt(forwardRealFFT.Waveform.Take(windowRange).Sum((w) => w * w));

            for (var i = 0; i <= windowRange; i++)
            {
                forwardRealFFT.Waveform[i] /= power;
            }

            FFT.Execute(forwardRealFFT.ForwardFFT);
            var tmpSpectrum = new Complex[fftSize / 2 + 1];

            Array.Copy(forwardRealFFT.Spectrum, tmpSpectrum, tmpSpectrum.Length);

            for (var i = 0; i < fftSize; i++)
            {
                forwardRealFFT.Waveform[i] *= i + 1.0;
            }
            FFT.Execute(forwardRealFFT.ForwardFFT);
            var spectrum = forwardRealFFT.Spectrum;

            for (int i = 0, limit = fftSize / 2; i <= limit; i++)
            {
                centroid[i] = spectrum[i].Real * tmpSpectrum[i].Real + spectrum[i].Imaginary * tmpSpectrum[i].Imaginary;
            }
        }
예제 #7
0
    public void GetFullSpectrumThreaded()
    {
        // We only need to retain the samples for combined channels over the time domain
        float[] preProcessedSamples = new float[numTotalSamples];

        int   numProcessed           = 0;
        float combinedChannelAverage = 0f;

        for (int i = 0; i < multiChannelSamples.Length; i++)
        {
            combinedChannelAverage += multiChannelSamples[i];

            // Each time we have processed all channels samples for a point in time, we will store the average of the channels combined
            if ((i + 1) % numChannels == 0)
            {
                preProcessedSamples[numProcessed] = combinedChannelAverage / numChannels;
                numProcessed++;
                combinedChannelAverage = 0f;
            }
        }

        Debug.Log("Combine Channels done");
        Debug.Log(preProcessedSamples.Length);

        // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
        int spectrumSampleSize = 1024;
        int iterations         = preProcessedSamples.Length / spectrumSampleSize;

        FFT fft = new FFT();

        fft.Initialize((UInt32)spectrumSampleSize);

        Debug.Log(string.Format("Processing {0} time domain samples for FFT", iterations));
        sampleChunk = new double[spectrumSampleSize];

        for (int i = 0; i < iterations; i++)
        {
            // Grab the current 1024 chunk of audio sample data
            Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

            // Apply our chosen FFT Window
            double[] windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
            double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
            double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

            // Perform the FFT and convert output (complex numbers) to Magnitude
            Complex[] fftSpectrum       = fft.Execute(scaledSpectrumChunk);
            double[]  scaledFFTSpectrum = DSPLib.DSP.ConvertComplex.ToMagnitude(fftSpectrum);
            scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

            // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
            float curSongTime = GetTimeFromIndex(i) * spectrumSampleSize;

            // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
            AnalyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), curSongTime);
        }

        Debug.Log("Spectrum Analysis done");
        Debug.Log("Background Thread Completed");
    }
예제 #8
0
    private void ProcessFullSpectrum()
    {
        //Prepare audio samples
        float[] preProcessedSamples = new float[totalSamples];

        int   numProcessed           = 0;
        float combinedChannelAverage = 0f;

        //Combine channels if the audio is stereo
        //Add to pre-processed array to be passed through the fft
        for (int i = 0; i < multiChannelSamples.Length; i++)
        {
            combinedChannelAverage += multiChannelSamples[i];

            //Store the average of the channels combined for a single time index
            if ((i + 1) % this.numberOfChannels == 0)
            {
                preProcessedSamples[numProcessed] = combinedChannelAverage / numberOfChannels;
                numProcessed++;
                combinedChannelAverage = 0f;
            }
        }

        //Execute an FFT to return the spectrum data over the time domain
        int totalIterations = preProcessedSamples.Length / spectrumSampleSize;

        //Instantiate and initialise a new FFT
        FFT fft = new FFT();

        fft.Initialize((uint)spectrumSampleSize);

        double[] sampleChunk = new double[spectrumSampleSize];
        for (int i = 0; i < totalIterations; i++)
        {
            //Get the current chunk of audio sample data
            Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

            //Apply an FFT Window type to the input data and calculate a scale factor
            double[] windowCoefficients  = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
            double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefficients);
            double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefficients);

            //Execute the FFT and get the scaled spectrum back
            Complex[] fftSpectrum = fft.Execute(scaledSpectrumChunk);
            //Convert the complex spectrum into a usable format of doubles
            double[] scaledFFTSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
            //Apply the window scale to the spectrum
            scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);


            //The magnitude values correspond to a single point in time
            float currentSongTime = GetTimeFromIndex(i) * spectrumSampleSize;

            //Send magnitude spectrum data to Spectral Flux Analyzer to be analyzed for peaks
            analyzer.AnalyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), currentSongTime);
        }

        Debug.Log("Spectrum Analysis done");
    }
예제 #9
0
        public void calculateSpectrum()
        {
            float watch = Time.realtimeSinceStartup;

            float[] preProcessedSamples = LoadMonoSound();

            // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
            FFTWindow = (int)Math.Pow(2, FFTWindowLog);
            ResizeSpectrum(preProcessedSamples.Length / FFTWindow * multisamples - (multisamples - 1), FFTWindow / 2);
            //float maximum = 0;

            FFT fft = new FFT();

            fft.Initialize((uint)FFTWindow);
            float[] windowCoefs = DSP.Window.Coefficients(filter, (uint)FFTWindow);
            float   scaleFactor = DSP.Window.ScaleFactor.Signal(windowCoefs);

            //Debug.Log(string.Format("Processing {0} time domain samples for FFT", chunks));
            float[] sampleChunk = new float[FFTWindow];
            for (int i = 0; i < chunks; i++)
            {
                // Grab the current 1024 chunk of audio sample data
                Array.Copy(preProcessedSamples, i * FFTWindow / multisamples, sampleChunk, 0, FFTWindow);

                // Apply our chosen FFT Window
                float[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                Complex[] fftSpectrum       = fft.Execute(scaledSpectrumChunk);
                float[]   scaledFFTSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
                //float curSongTime = getTimeFromIndex(i) * FFTWindow / multisamples;

                //Spectrum energy correction
                float hzPerBin = audioClip.frequency / FFTWindow;

                /*for (int x = 0; x < scaledFFTSpectrum.Length; x++)
                 * scaledFFTSpectrum[x] *= (x + 0.0f)*hzPerBin;*/
                //scaledFFTSpectrum[x] = Math.Max(0.0, 20.0 + Math.Max(-20.0, Math.Log(scaledFFTSpectrum[x], 2.0)));

                for (int x = 0; x < bins; x++)
                {
                    float rawValue = scaledFFTSpectrum[x + 1];//spectrum[0] - DC component (offset)
                    float fons     = calculateLoudness ? getFons((x + 1) * hzPerBin, rawValue) : rawValue;
                    //maximum = Mathf.Max (maximum, fons);
                    spectrumMap[i * bins + x] = fons;
                }

                // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
                //preProcessedSpectralFluxAnalyzer.analyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), curSongTime);
            }
            Debug.Log("FFT execution time = " + (Time.realtimeSinceStartup - watch) + " s.");
        }
예제 #10
0
        //-----------------------------------------------------------------------------
        // GetSmoothedPowerSpectrum() calculates the smoothed power spectrum.
        // The parameters used for smoothing are optimized in davance.
        //-----------------------------------------------------------------------------
        void GetSmoothedPowerSpectrum(double[] x, int fs, double currentF0, int fftSize, double currentPosition, ForwardRealFFT forwardRealFFT, double[] smoothedPowerSpectrum)
        {
            Array.Clear(forwardRealFFT.Waveform, 0, fftSize);
            GetWindowedWaveform(x, fs, currentF0, currentPosition, WindowType.Hanning, 4.0, forwardRealFFT.Waveform);

            FFT.Execute(forwardRealFFT.ForwardFFT);
            var spectrum = forwardRealFFT.Spectrum;

            for (int i = 0, limit = fftSize / 2; i <= limit; i++)
            {
                smoothedPowerSpectrum[i] = spectrum[i].Real * spectrum[i].Real + spectrum[i].Imaginary * spectrum[i].Imaginary;
            }
            Common.DCCorrection(smoothedPowerSpectrum, currentF0, fs, fftSize, smoothedPowerSpectrum);
            Common.LinearSmoothing(smoothedPowerSpectrum, currentF0, fs, fftSize, smoothedPowerSpectrum);
        }
예제 #11
0
    private void GetSpectrumData(float[] samples)
    {
        try{
            float[] preProcessedSamples = GetOutputData(samples);

            Debug.Log("Combine Channels done");
            Debug.Log(preProcessedSamples.Length);

            // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
            int spectrumSampleSize = 1024;
            int iterations         = preProcessedSamples.Length / spectrumSampleSize;

            FFT fft = new FFT();
            fft.Initialize((UInt32)spectrumSampleSize);

            Debug.Log(string.Format("Processing {0} time domain samples for FFT", iterations));
            double[] sampleChunk = new double[spectrumSampleSize];
            for (int i = 0; i < iterations; i++)
            {
                // Grab the current 1024 chunk of audio sample data
                Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

                // Apply our chosen FFT Window
                double[] windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
                double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
                double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                Complex[] fftSpectrum       = fft.Execute(scaledSpectrumChunk);
                double[]  scaledFFTSpectrum = DSPLib.DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
                float curSongTime = getTimeFromIndex(i) * spectrumSampleSize;

                // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
                preProcessedSpectralFluxAnalyzer.analyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), curSongTime);

                Debug.Log("Spectrum Analysis done");
                Debug.Log("Background Thread Completed");
            }
        } catch (Exception e) {
            Debug.Log(e.ToString());
        }
    }
예제 #12
0
        void GetNoiseSpectrum(int noiseSize, int fftSize, ForwardRealFFT forwardRealFFT)
        {
            var waveform = forwardRealFFT.Waveform;

            for (var i = 0; i < noiseSize; i++)
            {
                waveform[i] = Rand.Next();
            }

            var average = noiseSize > 0 ? waveform.Take(noiseSize).Average() : 1.0;

            for (var i = 0; i < noiseSize; i++)
            {
                waveform[i] -= average;
            }
            Array.Clear(waveform, noiseSize, fftSize - noiseSize);
            FFT.Execute(forwardRealFFT.ForwardFFT);
        }
예제 #13
0
        //-----------------------------------------------------------------------------
        // GetPowerSpectrum() calculates the power_spectrum with DC correction.
        // DC stands for Direct Current. In this case, the component from 0 to F0 Hz
        // is corrected.
        //-----------------------------------------------------------------------------
        void GetPowerSpectrum(int fs, double f0, ForwardRealFFT forwardRealFFT)
        {
            var halfWindowLength = MatlabFunctions.MatlabRound(1.5 * fs / f0);

            // FFT
            Array.Clear(forwardRealFFT.Waveform, halfWindowLength * 2 + 1, FFTSize - halfWindowLength * 2 - 1);
            FFT.Execute(forwardRealFFT.ForwardFFT);

            var powerSpectrum = forwardRealFFT.Waveform;
            var spectrum      = forwardRealFFT.Spectrum;

            for (int i = 0, limit = FFTSize / 2; i <= limit; i++)
            {
                powerSpectrum[i] = spectrum[i].Real * spectrum[i].Real + spectrum[i].Imaginary * spectrum[i].Imaginary;
            }

            Common.DCCorrection(powerSpectrum, f0, fs, FFTSize, powerSpectrum);
        }
예제 #14
0
파일: Form1.cs 프로젝트: wwkkww1983/COMplot
        private void SpectrumPrepare(int chanel, Chart PlotChart)
        {
            uint N = Convert.ToUInt32(saveDataTable.Rows.Count);

            double[] orignalData    = new double[N];
            double   samplingRateHz = 1000;
            string   windowFFT      = "Hamming";

            DSP.Window.Type windowToApply     = (DSP.Window.Type)Enum.Parse(typeof(DSP.Window.Type), windowFFT);
            double[]        wc                = DSP.Window.Coefficients(windowToApply, N);
            double          windowScaleFactor = DSP.Window.ScaleFactor.Signal(wc);
            // the sum of N and zeros must be power of 2.
            int pow2 = 1;

            while (N > Math.Pow(2, pow2))
            {
                pow2++;
            }
            uint zeros = Convert.ToUInt32(Math.Pow(2, pow2)) - N;
            // Instantiate & Initialize the FFT class
            FFT fft = new FFT();

            fft.Initialize(N, zeros);
            foreach (DataRow dr in saveDataTable.Rows)
            {
                // copy saveDataTable to array "orignailData"
                orignalData[saveDataTable.Rows.IndexOf(dr)] = Convert.ToDouble(dr[chanel]);
            }
            // remove the mean
            orignalData = DSP.Math.RemoveMean(orignalData);
            // Calculate the frequency span
            double[] fSpan = fft.FrequencySpan(samplingRateHz);
            // Convert and Plot Log Magnitude
            Complex[] cpxResult = fft.Execute(orignalData);

            double[] magResult = DSP.ConvertComplex.ToMagnitude(cpxResult);
            magResult = DSP.Math.Multiply(magResult, windowScaleFactor);
            double[] magLog = DSP.ConvertMagnitude.ToMagnitudeDBV(magResult);

            PlotChart.Series["Series1"].Points.Clear();
            PlotChart.Series["Series1"].Points.DataBindXY(fSpan, magResult);
        }
예제 #15
0
        //-----------------------------------------------------------------------------
        // GetPeriodicResponse() calculates an aperiodic response.
        //-----------------------------------------------------------------------------
        void GetPeriodicResponse(int fftSize, double[] spectrum, double[] aperiodicRatio, double currentVUV, double[] periodicResponse)
        {
            if (currentVUV <= 0.5 || aperiodicRatio[0] > 0.999)
            {
                periodicResponse.Fill(0.0, 0, fftSize);
                return;
            }

            var logSpectrum = MinimumPhase.LogSpectrum;

            for (int i = 0, limit = MinimumPhase.FFTSize / 2; i <= limit; i++)
            {
                logSpectrum[i] = Math.Log(spectrum[i] * (1.0 - aperiodicRatio[i]) + SafeGuardMinimum) / 2.0;
            }
            Common.GetMinimumPhaseSpectrum(MinimumPhase);
            Array.Copy(MinimumPhase.MinimumPhaseSpectrum, 0, InverseRealFFT.Spectrum, 0, fftSize / 2 + 1);

            FFT.Execute(InverseRealFFT.InverseFFT);
            MatlabFunctions.FFTShift(InverseRealFFT.Waveform.SubSequence(0, fftSize), periodicResponse);
            RemoveDCComponent(periodicResponse, fftSize, DCRemover, periodicResponse);
        }
예제 #16
0
        internal static void GetMinimumPhaseSpectrum(MinimumPhaseAnalysis minimumPhase)
        {
            var fftSize = minimumPhase.FFTSize;

            for (var i = fftSize / 2 + 1; i < fftSize; i++)
            {
                minimumPhase.LogSpectrum[i] = minimumPhase.LogSpectrum[fftSize - i];
            }

            FFT.Execute(minimumPhase.InverseFFT);
            var cepstrum = minimumPhase.Cepstrum;

            cepstrum[0] = new Complex(cepstrum[0].Real, cepstrum[0].Imaginary);
            for (int i = 1, limit = fftSize / 2; i < limit; i++)
            {
                cepstrum[i] = new Complex(cepstrum[i].Real * 2.0, cepstrum[i].Imaginary * -2.0);
            }
            cepstrum[fftSize / 2] = new Complex(cepstrum[fftSize / 2].Real, cepstrum[fftSize / 2].Imaginary * -1.0);
            for (var i = fftSize / 2 + 1; i < fftSize; i++)
            {
                cepstrum[i] = new Complex();
            }

            FFT.Execute(minimumPhase.ForwardFFT);

            // Since x is complex number, calculation of exp(x) is as following.
            // Note: This FFT library does not keep the aliasing.
            var mininimumPhaseSpectrum = minimumPhase.MinimumPhaseSpectrum;

            for (int i = 0, limit = fftSize / 2; i <= limit; i++)
            {
                var tmp       = Math.Exp(mininimumPhaseSpectrum[i].Real / fftSize);
                var real      = tmp * Math.Cos(mininimumPhaseSpectrum[i].Imaginary / fftSize);
                var imaginary = tmp * Math.Sin(mininimumPhaseSpectrum[i].Imaginary / fftSize);
                mininimumPhaseSpectrum[i] = new Complex(real, imaginary);
            }
        }
예제 #17
0
    public override float[] doFFT(float[] samples, WINDOW_TYPE window)
    {
        double[] dSamples = new double[samples.Length];
        for (int i = 0; i < samples.Length; i++)
        {
            dSamples[i] = (double)samples[i];
        }

        //Code from DSPLib documentation
        DSP.Window.Type dspWindow         = getWindowType(window);
        double[]        windowCoefs       = DSP.Window.Coefficients(dspWindow, (UInt32)this.binSize);
        double[]        windowInputData   = DSP.Math.Multiply(dSamples, windowCoefs);
        double          windowScaleFactor = DSP.Window.ScaleFactor.Signal(windowCoefs);

        System.Numerics.Complex[] complexSpectrum = fft.Execute(windowInputData);
        //Convert to magnitude and multiply by the window scale factor to get our binned array
        double[] fftSpectrum  = DSP.Math.Multiply(DSPLib.DSP.ConvertComplex.ToMagnitude(complexSpectrum), windowScaleFactor);
        float[]  fFFTSpectrum = new float[fftSpectrum.Length];
        for (int i = 0; i < fFFTSpectrum.Length; i++)
        {
            fFFTSpectrum[i] = (float)fftSpectrum[i];
        }
        return(fFFTSpectrum);
    }
예제 #18
0
        double D4CLoveTrainSub(double[] x, int fs, double currentF0, double currentPosition, int f0Length, int fftSize, int boundary0, int boundary1, int boundary2, ForwardRealFFT forwardRealFFT)
        {
            var powerSpectrum = new double[fftSize];

            var windowLength = MatlabFunctions.MatlabRound(1.5 * fs / currentF0) * 2 + 1;

            GetWindowedWaveform(x, fs, currentF0, currentPosition, WindowType.Blackman, 3.0, forwardRealFFT.Waveform);

            Array.Clear(forwardRealFFT.Waveform, windowLength, fftSize - windowLength);
            FFT.Execute(forwardRealFFT.ForwardFFT);

            var spectrum = forwardRealFFT.Spectrum;

            for (int i = boundary0 + 1, limit = fftSize / 2 + 1; i < limit; i++)
            {
                powerSpectrum[i] = spectrum[i].Real * spectrum[i].Real + spectrum[i].Imaginary * spectrum[i].Imaginary;
            }
            for (var i = boundary0; i <= boundary2; i++)
            {
                powerSpectrum[i] += powerSpectrum[i - 1];
            }

            return(powerSpectrum[boundary1] / powerSpectrum[boundary2]);
        }
예제 #19
0
        static void FastFFTFilt(double[] x, double[] h, int fftSize, ForwardRealFFT forwardRealFFT, InverseRealFFT inverseRealFFT, double[] y)
        {
            for (var i = 0; i < x.Length; i++)
            {
                forwardRealFFT.Waveform[i] = x[i] / fftSize;
            }
            if (x.Length < fftSize)
            {
                Array.Clear(forwardRealFFT.Waveform, x.Length, fftSize - x.Length);
            }
            FFT.Execute(forwardRealFFT.ForwardFFT);
            var xSpectrum = new Complex[fftSize];

            Array.Copy(forwardRealFFT.Spectrum, xSpectrum, fftSize / 2 + 1);

            for (var i = 0; i < h.Length; i++)
            {
                forwardRealFFT.Waveform[i] = h[i] / fftSize;
            }
            if (h.Length < fftSize)
            {
                Array.Clear(forwardRealFFT.Waveform, h.Length, fftSize - h.Length);
            }
            FFT.Execute(forwardRealFFT.ForwardFFT);

            for (var i = fftSize / 2 + 1; i > -1; i--)
            {
                inverseRealFFT.Spectrum[i] = new Complex(
                    xSpectrum[i].Real * forwardRealFFT.Spectrum[i].Real - xSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Imaginary,
                    xSpectrum[i].Real * forwardRealFFT.Spectrum[i].Imaginary + xSpectrum[i].Imaginary * forwardRealFFT.Spectrum[i].Real
                    );
            }
            FFT.Execute(inverseRealFFT.InverseFFT);

            inverseRealFFT.Waveform.BlockCopy(0, y, 0, fftSize);
        }
예제 #20
0
        static void Main()
        {
            FFT fft = new FFT();

            fft.Initialize(4096);

            double Fs = 1000;

            double[] d = new double[4096];
            for (int i = 0; i < 4096; i++)
            {
                double t = i / Fs;

                d[i] = Math.Sin(Math.PI * 2.0 * t * 200.0) + 0.2 * Math.Sin(Math.PI * 2.0 * t * 90.0);
            }

            var c = fft.Execute(d);



            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
예제 #21
0
        static void Main(string[] args)
        {
            const int FFTSize        = 240;
            const int FFTComplexSize = FFTSize / 2 + 1;
            var       fft            = new FFT(FFTSize, fftw_direction.Forward);
            var       input          = new Complex[FFTSize];
            var       input2         = new Complex[FFTSize];
            var       output         = new Complex[FFTSize];
            const int RectWaveWidth  = 40;
            const int RectWaveWidth2 = 30;
            var       conv           = new Convolver(Kernel);

            for (int i = 0; i < FFTSize; i++)
            {
                //input[i] = i / RectWaveWidth % 2 == 0 ? 1 : 0;
                //input[i] += i / RectWaveWidth2 % 2 == 0 ? 1 : 0;
                input[i] = 1000 + 50000 * Math.Sin(2 * Math.PI / FFTSize * 20.1 * i) + 40000 * Math.Sin(2 * Math.PI / FFTSize * 7 * i) + 9000 * Math.Sin(2 * Math.PI / FFTSize * 119 * i);
                // input[i] = 1 * Math.Sin(2 * Math.PI / FFTSize * 7 * i);
                // input[i] *= 2 * Math.Cos(2 * Math.PI / FFTSize * 5 * i);
            }

            var filter = new Complex[FFTSize];

            for (int i = 0; i < FFTSize; i++)
            {
                filter[i] = Filter(i, FFTSize);
            }

            //fixed (double* kernel = Kernel) {
            //	int len = conv.Convolve(input, FFTSize, input2, FFTSize);
            //	len = conv.ConvolveFinal(input2 + len, FFTSize - len);
            //}

            //input[0] = 1;
            //for (int i = 1; i < FFTSize; i++) {
            //	input[i] = 0;
            //}
            //for (int i = 0; i < FFTSize; i++) {
            //	input[i] = i % 2 == 0 ? 1 : 0;
            //}
            fft.WriteInput(input);
            fft.Execute();
            fft.ReadOutput(output);

            {
                var sum = 0d;
                for (int i = 0; i < output.Length; i++)
                {
                    var c   = output[i] / (i > 0 ? fft.FFTSize / 2 : FFTSize);
                    var abs = Complex.Abs(c);
                    sum += abs;
                    Console.WriteLine($"{i}=abs({c.Real:N6},{c.Imaginary:N6})={abs:N6}");
                }
                Console.WriteLine($"sum={sum:N6}");
            }

            //output[0] = 100 * FFTSize;
            //for (int i = 1; i < 50; i++) {
            //	output[i] = output[FFTSize - i] = 100 * FFTSize / 2;
            //}

            for (int i = 0; i < FFTSize; i++)
            {
                output[i] *= filter[i];
            }

            var ifft = new FFT(FFTSize, fftw_direction.Backward);

            ifft.WriteInput(output);
            ifft.Execute();
            ifft.ReadOutput(input2);

            for (int i = 0; i < input2.Length; i++)
            {
                input2[i] /= FFTSize;
            }

            fft.WriteInput(input2);
            fft.Execute();
            fft.ReadOutput(output);

            {
                var sum = 0d;
                for (int i = 0; i < output.Length; i++)
                {
                    var c   = output[i] / (i > 0 ? fft.FFTSize / 2 : FFTSize);
                    var abs = Complex.Abs(c);
                    sum += abs;
                    Console.WriteLine($"{i}=abs({c.Real:N6},{c.Imaginary:N6})={abs:N6}");
                }
                Console.WriteLine($"sum={sum:N6}");
            }
        }
예제 #22
0
    void AnalyzeAudio()
    {
        if (soundFile)
        {
            //The array for the averaged sample data. (L,R,L,R,L,R are averaged into (L+R)/2, (L+R)/2, (L+R)/2)
            float[] preprocessedSamples = new float[numSamples];

            int   numberOfSamplesProcessed = 0;
            float combinedChannelAverage   = 0f;

            Debug.Log("Starting sample processing...");
            for (int i = 0; i < allChannelsSamples.Length; i++)
            {
                combinedChannelAverage += allChannelsSamples[i];
                //for(int j = 0; j < numChannels; j++)
                //{
                //	combinedChannelAverage += allChannelsSamples[i + j];
                //	numberOfSamplesProcessed++;
                //}
                //preprecessedSamples[i/numChannels] = combinedChannelAverage / (float)numChannels;
                //combinedChannelAverage = 0;

                // Each time we have processed all channels samples for a point in time, we will store the average of the channels combined
                if ((i + 1) % numChannels == 0)
                {
                    preprocessedSamples[numberOfSamplesProcessed] = combinedChannelAverage / numChannels;
                    numberOfSamplesProcessed++;
                    combinedChannelAverage = 0f;
                }
            }

            int      specSampSize = 1024;
            int      iterations   = preprocessedSamples.Length / specSampSize;
            double[] sampleChunk  = new double[specSampSize];

            //LomFFT fft = new LomFFT();
            FFT fft = new FFT();
            fft.Initialize((System.UInt32)specSampSize);

            SpectralFluxAnalyzer preproAnalyzer = new SpectralFluxAnalyzer();

            for (int i = 0; i < iterations; ++i)
            {
                System.Array.Copy(preprocessedSamples, i * specSampSize, sampleChunk, 0, specSampSize);

                double[] windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)specSampSize);
                double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
                double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                System.Numerics.Complex[] fftSpectrum = fft.Execute(scaledSpectrumChunk);
                double[] scaledFFTSpectrum            = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                //old
                //fft.FFT(sampleChunk);



                float currTime = getTimeFromIndex(i) * specSampSize;
                preproAnalyzer.analyzeSpectrum(System.Array.ConvertAll(scaledFFTSpectrum, x => (float)x), currTime);                 //AnalyzeSpectrum(data...);
            }

            //foreach(SpectralFluxAnalyzer.SpectralFluxInfo specInfo in preproAnalyzer.spectralFluxSamples)
            //{
            //	if(specInfo.isPeak)
            //	{
            //		Debug.Log("Peak at: " + specInfo.time);
            //	}
            //}

            importantMoments = null;
            importantMoments = new AnimationCurve();
            freqCurve        = null;
            freqCurve        = new AnimationCurve();

            Debug.Log("Starting graph processing...");
            for (int i = 0; i < preproAnalyzer.spectralFluxSamples.Count; i++)
            {
                if (preproAnalyzer.spectralFluxSamples[i].isPeak)
                {
                    importantMoments.AddKey(preproAnalyzer.spectralFluxSamples[i].time, 1);
                    freqCurve.AddKey(preproAnalyzer.spectralFluxSamples[i].time, preproAnalyzer.spectralFluxSamples[i].spectralFlux);
                }
            }

            Debug.Log("Done!");
            Debug.Log(numberOfSamplesProcessed);


            //AudioListener.GetSpectrumData(spectrums, 0, FFTWindow.BlackmanHarris);
            //Debug.Log(AudioSettings.outputSampleRate);
        }
    }
예제 #23
0
    public void getFullSpectrumThreaded()   //not used. from https://medium.com/giant-scam/algorithmic-beat-mapping-in-unity-preprocessed-audio-analysis-d41c339c135a . //I find it well visualised, but overly sensitive (doesnt seem to target lower freq, which it should).
    {
        try {
            // We only need to retain the samples for combined channels over the time domain
            float[] preProcessedSamples = new float[this.samplesTotal]; //J- check here to see if needs doubling/halving.

            int   numProcessed           = 0;
            float combinedChannelAverage = 0f;
            for (int i = 0; i < CC.Length; i++)
            {
                combinedChannelAverage += CC[i];

                // Each time we have processed all channels samples for a point in time, we will store the average of the channels combined
                if ((i + 1) % 2 == 0)                                               //hard coding here, soz. J-
                {
                    preProcessedSamples[numProcessed] = combinedChannelAverage / 2; //here too (the 2).
                    numProcessed++;
                    combinedChannelAverage = 0f;
                }
            }

            Debug.Log("Combine Channels done");
            Debug.Log(preProcessedSamples.Length);

            // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
            int spectrumSampleSize = 1024;
            int iterations         = preProcessedSamples.Length / spectrumSampleSize;

            FFT fft = new FFT();
            fft.Initialize((UInt32)spectrumSampleSize);

            Debug.Log(string.Format("Processing {0} time domain samples for FFT", iterations));
            double[] sampleChunk = new double[spectrumSampleSize];
            for (int i = 0; i < iterations; i++)
            {
                // Grab the current 1024 chunk of audio sample data
                Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

                // Apply our chosen FFT Window
                double[] windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
                double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
                double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                System.Numerics.Complex[] fftSpectrum = fft.Execute(scaledSpectrumChunk);
                double[] scaledFFTSpectrum            = DSPLib.DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
                float curSongTime = getTimeFromIndex(i) * spectrumSampleSize;

                // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
                preProcessedSpectralFluxAnalyzer.analyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), curSongTime);
            }

            Debug.Log("Spectrum Analysis done");
            Debug.Log("Background Thread Completed");
        }
        catch (Exception e) {
            // Catch exceptions here since the background thread won't always surface the exception to the main thread
            Debug.Log(e.ToString());
        }
    }//Not used currently. Copied from giant-scam. Using for reference sporadically.
예제 #24
0
파일: FFT.cs 프로젝트: berkona/SharpBCI
        void DoFFT(EEGEvent evt)
        {
            // Do an FFT on each channel
            List <double[]> fftOutput = new List <double[]>();

            for (int i = 0; i < samples.Length; i++)
            {
                var channelSamples = samples[i];
                var samplesCopy    = channelSamples.ToArray();

                // apply windowing function to samplesCopy
                DSP.Math.Multiply(samplesCopy, windowConstants);

                var cSpectrum = fft.Execute(samplesCopy);
                // complex side smoothing
                //cSpectrum = complexFilters[i].Smooth(cSpectrum);

                double[] lmSpectrum = DSP.ConvertComplex.ToMagnitude(cSpectrum);
                lmSpectrum = DSP.Math.Multiply(lmSpectrum, scaleFactor);

                fftOutput.Add(lmSpectrum);
            }

            for (int i = 0; i < fftOutput.Count; i++)
            {
                var rawFFT = fftOutput[i];
                Add(new EEGEvent(evt.timestamp, EEGDataType.FFT_RAW, rawFFT, i));

                // magnitude side smoothing
                var smoothedFFT = magSmoothers[i].Smooth(rawFFT);
                Add(new EEGEvent(evt.timestamp, EEGDataType.FFT_SMOOTHED, smoothedFFT, i));
            }

            //var freqSpan = fft.FrequencySpan(sampleRate);

            // find abs powers for each band
            var absolutePowers = new Dictionary <EEGDataType, double[]>();

            for (int i = 0; i < channels; i++)
            {
                var    bins     = fftOutput[i];
                double deltaAbs = AbsBandPower(bins, 1, 4);
                double thetaAbs = AbsBandPower(bins, 4, 8);
                double alphaAbs = AbsBandPower(bins, 7.5, 13);
                double betaAbs  = AbsBandPower(bins, 13, 30);
                double gammaAbs = AbsBandPower(bins, 30, 44);
                //Logger.Log("D={0}, T={1}, A={2}, B={3}, G={4}", deltaAbs, thetaAbs, alphaAbs, betaAbs, gammaAbs);

                GetBandList(absolutePowers, EEGDataType.ALPHA_ABSOLUTE)[i] = (alphaAbs);
                GetBandList(absolutePowers, EEGDataType.BETA_ABSOLUTE)[i]  = (betaAbs);
                GetBandList(absolutePowers, EEGDataType.GAMMA_ABSOLUTE)[i] = (gammaAbs);
                GetBandList(absolutePowers, EEGDataType.DELTA_ABSOLUTE)[i] = (deltaAbs);
                GetBandList(absolutePowers, EEGDataType.THETA_ABSOLUTE)[i] = (thetaAbs);
            }

            // we can emit abs powers immediately
            Add(new EEGEvent(evt.timestamp, EEGDataType.ALPHA_ABSOLUTE, absolutePowers[EEGDataType.ALPHA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.BETA_ABSOLUTE, absolutePowers[EEGDataType.BETA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.GAMMA_ABSOLUTE, absolutePowers[EEGDataType.GAMMA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.DELTA_ABSOLUTE, absolutePowers[EEGDataType.DELTA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.THETA_ABSOLUTE, absolutePowers[EEGDataType.THETA_ABSOLUTE].ToArray()));

            // now calc and emit relative powers
            Add(new EEGEvent(evt.timestamp, EEGDataType.ALPHA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.ALPHA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.BETA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.BETA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.GAMMA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.GAMMA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.DELTA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.DELTA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.THETA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.THETA_ABSOLUTE)));
        }
예제 #25
0
    public void PerformFFTThreaded()
    {
        FFT fft = new FFT();

        fft.Initialize(GetSampleCount());
        double[] sampleChunk = new double[GetSampleCount()];

        while (GetNextChunkToRender(out int chunkId))
        {
            Color[][] bandColors = new Color[ColumnsPerChunk][];
            for (int k = 0; k < ColumnsPerChunk; k++)
            {
                int i = (chunkId * ColumnsPerChunk) + k;
                // Grab the current chunk of audio sample data
                int curSampleSize = (int)GetSampleCount();
                if (i * sampleOffset + GetSampleCount() > preProcessedSamples.Length)
                {
                    // We've reached the end of the track, pad with empty data
                    if (is3d)
                    {
                        waveformData.BandVolumes[i] = emptyArr;
                    }
                    else
                    {
                        waveformData.BandVolumes[i] = new float[(GetSampleCount() / 2) + 1];
                        if (FillEmptySpaceWithTransparency)
                        {
                            bandColors[k] = new Color[(GetSampleCount() / 2) + 1];
                        }
                        else
                        {
                            bandColors[k] = Enumerable.Repeat(spectrogramHeightGradient.Evaluate(0f), ((int)GetSampleCount() / 2) + 1).ToArray();
                        }
                    }
                    continue;
                }
                Buffer.BlockCopy(preProcessedSamples, (int)(i * sampleOffset) * sizeof(double), sampleChunk, 0, curSampleSize * sizeof(double));

                // Apply our chosen FFT Window
                double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                Complex[] fftSpectrum       = fft.Execute(scaledSpectrumChunk);
                double[]  scaledFFTSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                if (is3d)
                {
                    float[] bandVolumes = new float[_bands.Length - 1];
                    for (int j = 1; j < _bands.Length; j++)
                    {
                        bandVolumes[j - 1] = BandVol(_bands[j - 1], _bands[j], scaledFFTSpectrum, hzStep);
                    }
                    waveformData.BandVolumes[i] = bandVolumes;
                }
                else
                {
                    int gradientFactor = 25;
                    waveformData.BandVolumes[i] = scaledFFTSpectrum.Select(it => {
                        if (it >= Math.Pow(Math.E, -255d / gradientFactor))
                        {
                            return((float)((Math.Log(it) + (255d / gradientFactor)) * gradientFactor) / 128f);
                        }
                        return(0f);
                    }).ToArray();
                    bandColors[k] = waveformData.BandVolumes[i].Select(it =>
                    {
                        float lerp = Mathf.InverseLerp(0, 2, it);
                        return(spectrogramHeightGradient.Evaluate(lerp));
                    }).ToArray();
                }
            }

            if (!is3d)
            {
                // Render 2d texture with spectogram for entire chunk
                var data = waveformData.BandCData[chunkId];

                try {
                    int index = 0;
                    if (bandColors == null)
                    {
                        return;
                    }
                    for (int y = 0; y < bandColors[0].Length; y++)
                    {
                        for (int x = 0; x < bandColors.Length; x++)
                        {
                            data[index++] = bandColors[x][y];
                        }
                    }
                } catch (NullReferenceException) {
                    // Cancelled some other way
                } catch (InvalidOperationException) {
                    // NativeArray has been deallocated :(
                }
            }

            chunksComplete.Enqueue(chunkId);
            waveformData.ProcessedChunks++;
        }

        Debug.Log("FFT Thread Completed");
    }
예제 #26
0
        void process()
        {
            audioBuffer = new float[sampleCount * channels];
            audioSource.Read(audioBuffer, 0, sampleCount * channels);

            float[] preProcessedSamples = new float[sampleCount];

            int   numProcessed           = 0;
            float combinedChannelAverage = 0f;

            for (int i = 0; i < audioBuffer.Length; i++)
            {
                combinedChannelAverage += audioBuffer[i];

                // Each time we have processed all channels samples for a point in time, we will store the average of the channels combined
                if ((i + 1) % channels == 0)
                {
                    preProcessedSamples[numProcessed] = combinedChannelAverage / channels;
                    numProcessed++;
                    combinedChannelAverage = 0f;
                }
            }

            // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
            int spectrumSampleSize = 512;
            int iterations         = preProcessedSamples.Length / spectrumSampleSize;

            GlobalVariables.entryNo          = 0;
            GlobalVariables.times            = new float[iterations];
            GlobalVariables.thresholds       = new float[iterations];
            GlobalVariables.prunedSFValues   = new float[iterations];
            GlobalVariables.beats            = new bool[iterations];
            GlobalVariables.intensityChanged = new bool[iterations];
            GlobalVariables.intensityLevel   = new int[iterations];
            GlobalVariables.numBeats         = 0;

            FFT fft = new FFT();

            fft.Initialize((UInt32)spectrumSampleSize);

            SFAnalyser = new SpectralFluxAnalyser();

            double[] sampleChunk = new double[spectrumSampleSize];
            for (int i = 0; i < iterations; i++)
            {
                // Grab the current 1024 chunk of audio sample data
                Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

                // Apply our chosen FFT Window
                double[] windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
                double[] scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
                double   scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

                // Perform the FFT and convert output (complex numbers) to Magnitude
                Complex[] fftSpectrum       = fft.Execute(scaledSpectrumChunk);
                double[]  scaledFFTSpectrum = DSPLib.DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
                float curSongTime = getTimeFromIndex(i) * spectrumSampleSize;

                // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
                SFAnalyser.analyseSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x), curSongTime);
            }
        }
예제 #27
0
        private void GetSpectrum(uint dataNumber)
        {
            string[] textBoxRaw;

            if (dataNumber == 1)
            {
                if (String.IsNullOrEmpty(textBoxData1.Text))
                {
                    return;
                }

                if (String.IsNullOrEmpty(textBoxFreq1.Text))
                {
                    MessageBox.Show("Input sampling rate");
                    return;
                }

                textBoxRaw = textBoxData1.Text.Split('\n');
            }
            else
            {
                if (String.IsNullOrEmpty(textBoxData2.Text))
                {
                    return;
                }

                if (String.IsNullOrEmpty(textBoxFreq2.Text))
                {
                    MessageBox.Show("Input sampling rate");
                    return;
                }

                textBoxRaw = textBoxData2.Text.Split('\n');
            }

            int  len       = textBoxRaw.Length;
            uint padLength = 0;

            double[] inputData = new double[len];
            int      i         = 0;

            for (int j = 0; ; j++)
            {
                if (Math.Pow(2, j) > len)
                {
                    padLength = Convert.ToUInt32(Math.Pow(2, j));
                    break;
                }
            }

            if (dataNumber == 1)
            {
                labelData1Count.Text = "Data #1 Count : " + len;
            }
            else
            {
                labelData2Count.Text = "Data #2 Count : " + len;
            }

            foreach (string data in textBoxRaw)
            {
                if (String.IsNullOrEmpty(data) || String.IsNullOrWhiteSpace(data))
                {
                    continue;
                }

                inputData[i] = Convert.ToDouble(data);
                i++;
            }

            FFT fft = new FFT();

            fft.Initialize((uint)len, (uint)(padLength - len));

            Complex[] cpx = fft.Execute(inputData);

            double[] sptr = DSP.ConvertComplex.ToMagnitude(cpx);

            Array.Resize(ref sptr, sptr.Length / 2);

            double[] freqSpan;

            if (dataNumber == 1)
            {
                freqSpan = fft.FrequencySpan(double.Parse(textBoxFreq1.Text));
            }
            else
            {
                freqSpan = fft.FrequencySpan(double.Parse(textBoxFreq2.Text));
            }

            Array.Resize(ref freqSpan, freqSpan.Length / 2);

            Plot plot = new Plot("FFT Spectrum Display", "FFT Bin (Freq. = x * 2)", "Magnitude (Vrms)");

            plot.PlotData(freqSpan, sptr);
            plot.Show();
        }
예제 #28
0
        /// <summary>
        /// This class is used to process the AudioClip.
        /// It uses FFT to read the samples, afterwards a Spectral Flux Analysis is performed.
        /// This class was not modified compared to the original.
        /// </summary>
        private void GetAudioSpectrum()
        {
            try
            {
                // We only need to retain the samples for combined channels over the time domain
                var preProcessedSamples = new float[_numTotalSamples];

                var numProcessed           = 0;
                var combinedChannelAverage = 0f;
                for (var i = 0; i < _multiChannelSamples.Length; i++)
                {
                    combinedChannelAverage += _multiChannelSamples[i];

                    // Each time we have processed all channels samples for a point in time, we will store the average of the channels combined
                    if ((i + 1) % _numChannels == 0)
                    {
                        preProcessedSamples[numProcessed] = combinedChannelAverage / _numChannels;
                        numProcessed++;
                        combinedChannelAverage = 0f;
                    }
                }

                Debug.Log("Combine Channels done");
                Debug.Log(preProcessedSamples.Length);

                // Once we have our audio sample data prepared, we can execute an FFT to return the spectrum data over the time domain
                var spectrumSampleSize = 1024;
                var iterations         = preProcessedSamples.Length / spectrumSampleSize;

                var fft = new FFT();
                fft.Initialize((uint)spectrumSampleSize);

                Debug.Log($"Processing {iterations} time domain samples for FFT");
                var sampleChunk = new double[spectrumSampleSize];
                for (var i = 0; i < iterations; i++)
                {
                    // Grab the current 1024 chunk of audio sample data
                    Array.Copy(preProcessedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

                    // Apply our chosen FFT Window
                    var windowCoefs         = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
                    var scaledSpectrumChunk = DSP.Math.Multiply(sampleChunk, windowCoefs);
                    var scaleFactor         = DSP.Window.ScaleFactor.Signal(windowCoefs);

                    // Perform the FFT and convert output (complex numbers) to Magnitude
                    var fftSpectrum       = fft.Execute(scaledSpectrumChunk);
                    var scaledFFTSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                    scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                    // These 1024 magnitude values correspond (roughly) to a single point in the audio timeline
                    var curSongTime = GetTimeFromIndex(i) * spectrumSampleSize;

                    // Send our magnitude data off to our Spectral Flux Analyzer to be analyzed for peaks
                    _analyzer.analyzeSpectrum(Array.ConvertAll(scaledFFTSpectrum, x => (float)x),
                                              curSongTime);
                }

                Debug.Log("<<< Spectrum Analysis finished successfully >>>");
            }
            catch (Exception e)
            {
                // Catch exceptions here since the background thread won't always surface the exception to the main thread
                Debug.Log(e.ToString());
            }
        }
예제 #29
0
 private double[] CreateFrequencyHistogramFromPcmSlices(Int16[] pcmSampleAmplitudes)
 {
     LoadFftBuffer(pcmSampleAmplitudes);
     return(DSP.ConvertComplex.ToMagnitude(fft.Execute(fftBuffer)));
 }
예제 #30
0
    private void AnalyzeFullSpectrum()
    {
        try
        {
            //We only retain the samples of combined channel over the time domain
            float[] processedSamples = new float[totalNumberOfSamples];

            int   numProcessed   = 0;
            float channelAverage = 0f;

            for (int i = 0; i < multiChannelSamples.Length; ++i)
            {
                channelAverage += multiChannelSamples[i];

                //Store the average of the combined channels
                if ((i + 1) % numberOfChannels == 0)
                {
                    processedSamples[numProcessed] = channelAverage / numberOfChannels;
                    ++numProcessed;
                    channelAverage = 0f;
                }
            }

            //Debug.Log("Channel combining done. Total number of samples processed: " + processedSamples.Length);

            //Execute Fast-Fourier Transform to return the spectrum data over time
            int spectrumSampleSize = 1024;
            int iterations         = processedSamples.Length / spectrumSampleSize;

            FFT fft = new FFT();
            fft.Initialize((System.UInt32)spectrumSampleSize);

            double[] sampleChunk = new double[spectrumSampleSize];
            for (int i = 0; i < iterations; ++i)
            {
                //Grab the current 1024 chunk of audio data
                System.Array.Copy(processedSamples, i * spectrumSampleSize, sampleChunk, 0, spectrumSampleSize);

                //Apply FFT
                double[] windowCoEf        = DSP.Window.Coefficients(DSP.Window.Type.Hanning, (uint)spectrumSampleSize);
                double[] scaledSampleChunk = DSP.Math.Multiply(sampleChunk, windowCoEf);
                double   scaleFactor       = DSP.Window.ScaleFactor.Signal(windowCoEf);

                //Perform FFT and convert output to magnitude
                Complex[] fftSpectrum       = fft.Execute(scaledSampleChunk);
                double[]  scaledFFTSpectrum = DSP.ConvertComplex.ToMagnitude(fftSpectrum);
                scaledFFTSpectrum = DSP.Math.Multiply(scaledFFTSpectrum, scaleFactor);

                //Convert the chunk values to a single point within audio timeline
                float currSongtime = GetSongtime(i) * spectrumSampleSize;

                //Analyze multitude data using SpectrumAnalyzer to detect peaks
                spectrumAnalyzer.AnalyzeSpectrum(System.Array.ConvertAll(scaledFFTSpectrum, x => (float)x), currSongtime);
            }

            //Debug.Log("Spectrum Analysis completed, now getting all Peak data samples.");
            for (float i = 0f; i <= clipLength; i += 0.0167f)
            {
                //Get the index from the audio time
                int index = GetIndex(i) / spectrumAnalyzer.numSamples;

                //Only run if index returned is within range of the spectrum analyzer sample-list
                if (index < spectrumAnalyzer.spectralFluxSamples.Count)
                {
                    SpectralFluxInfo info = spectrumAnalyzer.spectralFluxSamples[index];

                    //Make sure sample is a peak
                    if (info.isPeak)
                    {
                        peakInfo.Add(info);
                    }
                }
            }

            //Debug.Log("Spectrum Analysis and Peak Sampling done. Thread completed.");
            peakInfoSize = peakInfo.Count;
            isDone       = true;
        }
        catch (System.Exception ex)
        {
            //Error logging
            Debug.LogError(ex.ToString());
        }
    }