Small summarized on the audio FFT analysis

Section of this article to learn knowledge from the following article:

https://zhuanlan.zhihu.com/p/19763358  knowledge Fourier transform

https://www.cnblogs.com/RabbitHu/p/FFT.html knowledge of FFT

 

In the recent work done on the content of the music game, which need to be analyzed to find the rhythm of the audio point (or a stress point).

After studying a series of related knowledge, we learned a waveform diagram of a piece of music can be decomposed into a waveform diagram of different frequencies, that is, from the time domain to the frequency domain.

FIG use other bloggers easier to understand, as shown below.

Wave from the time domain to the frequency domain conversion by Fourier transform, the Fourier transform knowledge can learn the most from the link above or find one (Fourier really amazing !!!).

Computer processing is discrete audio data in the time domain, we use a discrete Fourier transform DFT (Fourier transform in the time domain and frequency domain were tested discrete form) obtained in the discrete frequency domain data.

Fast Fourier Transform (FFT) algorithm is fast DFT, the core idea is DFT divide and conquer method , specific derivation can see the second link above.

FFT code is as follows:

     static void BitReverse(Complex[] cpData, int n)
        {
            Complex temp;
            int lim = 0;
            while ((1 << lim) < n) lim++;
            for (int i = 0; i < n; i++)
            {
                int t = 0;
                for (int j = 0; j < lim; j++)
                {

                    if (((i >> j) & 1) != 0)
                        t |= (1 << (lim - j - 1));
                }
                if (i < t)
                {
                    temp = cpData[i];
                    cpData[i] = cpData[t];
                    cpData[t] = temp;
                } // i < t 防止交换两次
            }
        }

        static void FFT1(Complex[] cpData, bool forward)
        {
            var n = cpData.Length;
 
            BitReverse(cpData, n);//位反转

            Complex[] omg = new Complex[n];
            for (int i = 0; i < n; i++)
            {
                omg[i] = new Complex((float)Math.Cos(2 * Math.PI * i / n), (float)Math.Sin(2 * Math.PI * i / n));
            }
             Complex temp ;
            for (int step = 2; step <= n; step *= 2)
            {
                int m = step / 2;
                for (int j = 0; j < n; j += step)
                    for (int i = 0; i < m; i++)
                    {//蝶形运算
                        if(forward)
                            temp = omg[n / step * i] * cpData[j + i + m];
                        else
                            temp = omg[n / step * i].Conjugate() * cpData[j + i + m];
                        cpData[j + i + m] = cpData[j + i] - temp;
                        cpData[j + i] = cpData[j + i] + temp;
                    }
            }
        }

Complex is a complex package of classes, lazy did not write, from the brother https://blog.csdn.net/u011583927/article/details/46974341

The FFT, new objects a lot, not very efficient. . .

A paste directly to the complex real and imaginary portions alternately in a direct count of the array can be faster.

     static void Reverse(float[] data, int n)
        {
                                                           
            int j = 0, k = 0;                                                        
            var top = n / 2;                                                   
            while (true)
            {
                                                 
                var t = data[j + 2];
                data[j + 2] = data[k + n];
                data[k + n] = t;
                t = data[j + 3];
                data[j + 3] = data[k + n + 1];
                data[k + n + 1] = t;
                if (j > k)
                {                                                                           
                    t = data[j];
                    data[j] = data[k];
                    data[k] = t;
                    t = data[j + 1];
                    data[j + 1] = data[k + 1];
                    data[k + 1] = t;
                                                                             
                    t = data[j + n + 2];
                    data[j + n + 2] = data[k + n + 2];
                    data[k + n + 2] = t;
                    t = data[j + n + 3];
                    data[j + n + 3] = data[k + n + 3];
                    data[k + n + 3] = t;
                }
                                                                                   
                k += 4;
                if (k >= n)
                    break;
                                                                                 
                var h = top;
                while (j >= h)
                {
                    j -= h;
                    h /= 2;
                }
                j += h;
            }                                                                            
        }
        static void FFT2(float[] data, bool forward)
        {
            var n = data.Length;            
            n /= 2;

            Reverse(data, n);


            float sign = forward ? 1 : -1;
            var mmax = 1;
            while (n > mmax)
            {
                var istep = 2 * mmax;
                var theta = sign * (float)Math.PI / mmax;
                float wr = 1, wi = 0;
                var wpr = (float)Math.Cos(theta);
                var wpi = (float)Math.Sin(theta);
                for (var m = 0; m < istep; m += 2)
                {
                    for (var k = m; k < 2 * n; k += 2 * istep)
                    {
                        var j = k + istep;
                        var tempr = wr * data[j] - wi * data[j + 1];
                        var tempi = wi * data[j] + wr * data[j + 1];
                        data[j] = Data [k] - tempr; 
                        Data [j + 1 ] = Data [k + 1 ] - tempi; 
                        Data [k] = Data [k] + tempr; 
                        Data [k + 1 ] = Data [k + 1 ] + tempi; 
                    } 
                    Var t = wr;                                                              
                    wr = wr * WPR - wi * WPI; 
                    wi = wi * WPR + t * WPI; 
                } 
                Mmax = Istep; 
            }

        }

     static void Main(string[] args)
        {

            int n =1024*512;
            float[] data = new float[2 * n];
            for (int i = 0; i < n; i++)
            {
                data[2 * i] = i;
                data[2 * i + 1] = 0;
            }

            Complex[] cpData = new Complex[n];
            for (int i = 0; i < n; i++)
            {
                cpData[i] = new Complex(data[2 * i], data[2 * i + 1]);
            }

            long s = DateTime.Now.Ticks;
            FFT1(cpData, true);
            Console.WriteLine("time:" + (DateTime.Now.Ticks - s) / 10000);
            
            s = DateTime.Now.Ticks;
            FFT2(data, true);
            Console.WriteLine("time:" + (DateTime.Now.Ticks - s) / 10000);

            Console.Read();
        }

 Or worse with a lot of speed. . .

 

After a good process for obtaining frequency data is no longer so burn the brain (blame their own early in the Fourier transform back to the textbook). . .

Find the rhythm logical point probably as follows (the code a bit more is not posted):

1. Obtain the data sequentially according to the sampling rate, each time a set of complex obtained by the FFT array.

2. Calculate the complex die length, may represent a sound volume at this frequency range of the sound can be added together, can be used to represent bass, midrange, treble.

3. Comparison of the data changes for each frame can be judged rhythm point (large change in sound, may indicate a rhythm point).

In fact, to get the value of the frequency domain, for different functions, we can be back on the free play.

Guess you like

Origin www.cnblogs.com/pj2933/p/11295687.html
FFT