【问题标题】:FFT of wav file using C++ / Python使用 C++/Python 对 wav 文件进行 FFT
【发布时间】:2017-09-11 12:26:45
【问题描述】:

我一直在广泛使用谷歌搜索,可以使用 Python 绘制我的 wav 文件的 FFT,但我无法为 C++ 这样做,而我最初必须这样做。 我下载了 FFTW 和 LIBSND 并将其链接到 Visual C++。 虽然我不了解在库中使用哪些函数以及发送什么来计算与 Python 中相同的结果。

问题:我基本上首先不明白,如何获得幅度,频率的数组,然后我将继续绘制它们。

我的 C++ 代码是: `

//.........................np.fft.fft as in python
p = fftw_plan_dft_1d(num_items, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); 
fftw_execute(p);

//According to Nyquist its 1/2
for (int i = 0; i < num_items / 2; ++i) {
            printf("real=%f ",out[i][0]);
            printf("img=%f ",out[i][1]);
        }

//Amplitude
float *amp;
amp = (float *)malloc(sizeof(float)*(num_items / 2));
for (int i = 0; i < num_items/2; ++i) {
    amp[i] = sqrt( pow(out[i][0],2) + pow(out[i][1], 2));
}`

这是它的python代码。

import sys
import numpy as np
from scipy.io.wavfile import read
from matplotlib import pyplot as plt


def do_fft(received_wave, Fs=44100):
    """
    :param received_wave: wave file data.
    :param Fs: Sampling Rate, default = 44100
    :return: [Frequency, Amplitude]
    """

    # Calculating the fft coeff and amp sqrt(x^2+y^2)
    fft_coeff   = np.fft.fft(received_wave)
    Amp         = np.sqrt(np.abs(fft_coeff))


    print "FFT_coeff: ",fft_coeff
    print "Amp: ",Amp 

    # calulating size of recieved wave data and creating a freq array based on sampling freq Fs and size
    size1=len(received_wave)
    freq=np.linspace(0,Fs,size1)

    print "Length of recieved wave: ",size1;

    # Taking only half sample based on Nyquist-Shannon sampling theorem for ampiltude and frequency
    # https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem
    Amplitude  = Amp[0:int(size1/2)]
    Frequency = freq[0:int(size1/2)]


    print "\nAmplitude : ", Amplitude
    print "\nFreq : ", Frequency
    # This shorts the  index of the array in acending order
    idx = np.argsort(Amplitude)
    # freq1 is the maximum freq freq2 second maximum and so on
    freq1 = ((idx[-1]) / float(size1)) * Fs  
    freq2 = ((idx[-2]) / float(size1)) * Fs
    freq3 = ((idx[-3]) / float(size1)) * Fs

    return Amplitude, Frequency, freq1, freq2, freq3


def read_from_file(file_location):
    """
    Read file ad return audio data
    :param file_location: location of file.
    :return: audio data
    """

    data = read(file_location)


    # as scipy read function return two array [sample_rate_of_file, [audio_chunks]]
    sample_rate, audio_data = data
    print "Data: " ,data
    for i in range(len(audio_data)):
     #   print audio_data[i]
         pass

    print i
    return sample_rate, audio_data

def plot_fft(audio_file):

    # read audio chunks from audio file
    sample_rate, audio_data = read_from_file(audio_file)

    # call do_fft() function to get fft ( frequency and amplitude)
    Amplitude, Frequency, freq1, freq2, freq3 = do_fft(received_wave=audio_data, Fs=sample_rate)

    # plot fft
    plt.title("FFT heigest : {}, second_heigest : {}".format(freq1, freq2))
    plt.plot(Frequency, Amplitude)
    plt.show()
    plt.close()

    return True


if __name__ == '__main__':
    file = "hellotrill.wav"
    plot_fft(file)

我不明白,因为我在 Python 和 C++ 中得到的数组完全不同。

【问题讨论】:

    标签: python c++ audio fftw libsndfile


    【解决方案1】:

    如果你想绘制一些东西,你需要使用一个可以绘制图形或为另一个程序生成数据的库。

    许多 选项 - 您可以使用以下几个选项:

    Qt

    SFML

    SDL

    gnuplot

    C++ 标准库不提供任何开箱即用的图形功能。

    【讨论】:

    • 感谢您的回答。虽然我更多地关注如何计算 FFT 并获得幅度和频率 freq1,freq2,fre3,如 python 所示。我也会再次编辑问题。
    【解决方案2】:

    我转换了代码并使用 Gnuplot 成功地绘制了它。代码如下,在 Visual Studio 2017 中完成(因此是 stdafx.h 头文件)

    #include "stdafx.h"
    #include<fftw3.h>
    #include<sndfile.h>
    
    #include<fstream>
    #include<vector>
    #include<math.h>
    #include <algorithm>
    #include<iostream>
    using namespace std;
    
    #define file_path "F:/Shivansh Work/University work/VIT/Assignment2/hellotrill.wav"
    
    
    //Read http://www.fftw.org/fftw3_doc/Complex-One_002dDimensional-DFTs.html#Complex-One_002dDimensional-DFTs
    
    void plot_fft(float *amp, float *freq, float *freq2,int num_items, int Fs) {
    
    fstream amp_freq;
    amp_freq.open("fft_plot.txt", fstream::out);
    for (int i = 0; i < num_items/2; ++i)
    {
        amp_freq << freq2[i] << " " << amp[i] << std::endl;
    }
    amp_freq.close();
    
    
    float *idx; // amplitude array for sorting
    idx= (float *)malloc(sizeof(float)*(num_items / 2));
    for (int i = 0; i < num_items / 2; ++i) {
        idx[i] = amp[i] ;   
    }
    
    int size= num_items / 2;
    sort(idx, idx + size);
    cout << idx[size - 1] << " " << amp[size - 1];
    //NOTE: np.argsort returns the indices of sorted array, but not the values itself
    float fre1, fre2, fre3;
    fre1 = Fs*idx[size - 1]/ (float)num_items;
    fre2 = Fs*idx[size - 2]/ (float)num_items;
    fre3 = Fs*idx[size - 3]/ (float)num_items;
    
    printf("\n\nHighest frequencies: %.5f, %.5f, %.5f", fre1, fre2, fre3);
    printf("\n[NOTE: In given python code: np.argsort returns the indices of sorted array, but not the values itself]");
    printf("\n\nThe amplitude and frequency have been written in the file fft_plot.txt");
    

    }

    int main() {
    
    char        *infilename;
    SNDFILE     *file = NULL;
    
    SF_INFO     sfinfo;
    int num_channels;
    int num, num_items;
    double *buf;
    int frame, samplerate, ch;
    int i, j;
    
    FILE        *outfile = NULL;
    
    //Read the file, into buffer
    file = sf_open(file_path, SFM_READ, &sfinfo);
    
    
    /* Print some of the info, and figure out how much data to read. */
    frame = sfinfo.frames;
    samplerate = sfinfo.samplerate;
    ch = sfinfo.channels;
    printf("frames=%d\n", frame);
    printf("samplerate=%d\n", samplerate);
    printf("channels=%d\n", ch);
    num_items = frame * ch;
    printf("num_items=%d\n", num_items);
    
    
    
    //Allocate space for the data to be read, then read it
    buf = (double *)malloc(num_items * sizeof(double));
    num = sf_read_double(file, buf, num_items);
    
    sf_close(file);
    printf("Read %d items\n", num);
    
    
    /*initialize FFT parameters*/
    fftw_complex *in, *out;
    fftw_plan p;
    /*Do fft to wav data*/
    in = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * num_items);
    out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * num_items);
    for (int i = 0; i < num_items; i++) {
        in[i][0] = buf[i];
        in[i][1] = 0;
    }
    //.........................np.fft.fft as in python (OUT stores fft_coeff)
    p = fftw_plan_dft_1d(num_items, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);     //1D Complex DFT, FFTW_FORWARD & BACKWARD just give direction and have particular values
    fftw_execute(p);
    
    
    /*  //According to Nyquist its 1/2
    for (int i = 0; i < num_items / 2; ++i) {
                printf("%f+",out[i][0]);
                printf("%fj  ",out[i][1]);
            }
    */
    
    //...............................Amplitude
    float *amp;
    amp = (float *)malloc(sizeof(float)*(num_items / 2));
    for (int i = 0; i < num_items/2; ++i) {
        amp[i] = sqrt (sqrt( pow(out[i][0],2) + pow(out[i][1], 2)));        //2 sqrt since np.sqrt( np.abs() )
    }
    fftw_destroy_plan(p);
    
    
    //...............................Frequency
    float *freq;
    freq = (float *)malloc(sizeof(float)*(num_items/2));
    int size = samplerate / num_items;
    
    double *samples;
    samples = (double *)malloc(sizeof(double)*samplerate);     //Multiplying by sample rate cuz of np.linspace, goes from 0-samplerate
    sf_read_double(file, samples, samplerate);
    
    fftw_complex* out2 = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * num_items);
    fftw_plan plan;
    plan = fftw_plan_dft_r2c_1d(num_items, samples, out2, FFTW_ESTIMATE);   //out2 imaginary parts are all 0, can read http://stackoverflow.com/questions/4364823/how-do-i-obtain-the-frequencies-of-each-value-in-an-fft
    fftw_execute(plan);
    
    for (int i = 0; i<num_items/2; i++) 
    {
        freq[i] = sqrt(pow(out2[i*size][0],2) + pow(out2[i*size][1],2));//np.linspace (0-Fs ,in size1 increments), also can read http://stackoverflow.com/questions/4364823/how-do-i-obtain-the-frequencies-of-each-value-in-an-fft
    }
    //NOTE: In np.linspace(0,44100,29757) -> a normal array is created with numbers. Not actual frequency. 
    //But here actual frequency is being created
    
    fftw_destroy_plan(plan);
    fftw_free(out2); fftw_free(in); fftw_free(out);
    
    
    //................................Function for frequency according to python program
    float *freq2;
    freq2 = (float *)malloc(sizeof(float)*(num_items / 2));
    
    float size2 = ( float)samplerate / (float)num_items;
    for (int i = 0; i<= num_items / 2; i++)
    {
        freq2[i] = i*size2;
    }
    
    //..................................Plotting
    plot_fft(amp, freq, freq2, num_items,samplerate);
    
    return 0;
    

    }

    数组已转换为文本文件,如 plot_fft 函数所示。然后很容易在gnuplot中绘制出来。

    绘图功能 设置样式线 1 lc rgb '#0060ad' lt 1 lw 2 pt 7 ps 1.5 #--- 蓝色 用linespoints ls 1绘制'fft_plot.dat'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-16
      • 2015-02-03
      • 2016-05-30
      • 1970-01-01
      • 2014-03-16
      • 2014-09-16
      • 2016-11-23
      • 1970-01-01
      相关资源
      最近更新 更多