实时音频处理

时间:2014-06-03 15:05:33

标签: c++ qt audio real-time fftw

我想用Qt 进行 实时音频处理 使用FFTW3 显示基频。

我已经完成的步骤:

  1. 我从计算机设备捕获任何声音并将其填入缓冲区。
  2. 我将声音样本分配给double数组
  3. 我计算基频。
  4. 问题

    我的代码始终将 0 作为基频返回。

    QByteArray *buffer;
    QAudioInput *audioInput;
    audioInput = new QAudioInput(format, this);
    
    //Check the number of samples in input buffer
    qint64 len = audioInput->bytesReady();
    
    //Limit sample size
    if(len > 4096)
        len = 4096;
    
    //Read sound samples from input device to buffer
    qint64 l = input->read(buffer.data(), len);
    
    if(l > 0)
    {
        int input_size = BufferSize;
    
        // Compute corresponding number of complex output samples
        int output_size = (input_size/2 + 1);
        double *input_buffer = static_cast<double*>(fftw_malloc(input_size * sizeof(double)));
        fftw_complex *out = static_cast<fftw_complex*>(fftw_malloc(output_size * sizeof(fftw_complex)));
    
        //Assign sound samples to double array
        input_buffer = (double*)buffer.data();
        fftw_plan p3;
    
        //Create plan
        p3 = fftw_plan_dft_r2c_1d(input_size, input_buffer, out, FFTW_ESTIMATE);
    
        fftw_execute(p3);
        double reout[BufferSize];
        double imgout[BufferSize];
        double magnitude[BufferSize/2];
    
        long ffond = 0.0; // Position of the frequency
        double max = 0; // Maximal amplitude
    
        for (int i = 0; i < BufferSize/2; i++)
        {
            reout[i] = out[i][0];
            imgout[i] = out[i][1];
            cout << imgout[i] << endl;
            magnitude[i] = sqrt(reout[i]*reout[i] + imgout[i]*imgout[i]); //Calculate magnitude of first
            double t = sqrt(reout[i]*reout[i] + imgout[i]*imgout[i]);
    
            if(t > max)
            {
                max = t;
                ffond = i;
            }
        }
    
        qDebug() << "fundamental frequency is :" << QString::number(ffond*static_cast<double>);
        fftw_destroy_plan(p3);
    

1 个答案:

答案 0 :(得分:1)

我可以看到两个直接的问题:

  1. 你没有应用window function,因此会有相当多的spectral leakage和相关的“拖尾”光谱(可能是一个大的DC(0 Hz)组件与相关的“裙子” “)

  2. 你假设频谱中最大的幅度是基频,这很可能是不正确的,原因有两个:(a)你可能有一个大的0 Hz分量,大于你的基频或谐波和(b)取决于你试图分析的声音的性质,基波的幅度可能小于谐波(甚至可能完全没有)

  3. 我建议你做以下事情:

    • 在FFT之前应用合适的window function - 这应该可以更好地定义峰值,并且应该减少0 Hz处的伪影

    • 在适当的bin而不是0开始搜索,例如如果你感兴趣的最低基频是50赫兹,那么从相应的箱子开始50赫兹而不是0

    • 添加调试选项以图形方式显示光谱 - 当您想知道为什么结果没有意义时,这种可视化调试辅助工具将会有很大帮助

    • 如果你真正想要测量的是音高而不是基频,那么请阅读pitch detection algorithms,例如谐波产品频谱 - 这比尝试识别基频的天真方法(其频率与一般情况下的音高不同)要好得多。