The Man
The Man

Reputation: 427

Real time audio processing

I would like to make real time audio processing with Qt and display the fundamental frequency using FFTW3.

What I've done in steps:

  1. I capture any sound from computer device and fill it into the buffer.
  2. I assign sound samples to double array
  3. I compute the fundamental frequency.

Problem

My code always returns 0 as fundamental frequency.

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);

Upvotes: 2

Views: 2517

Answers (1)

Paul R
Paul R

Reputation: 212929

You have two immediate problems that I can see:

  1. you are not applying a window function, so there will be considerable spectral leakage and associated "smearing" of the spectrum (and probably a large DC (0 Hz) component with associated "skirt")

  2. you are assuming that the largest magnitude in the spectrum is the fundamental frequency, which will most likely be incorrect for two reasons: (a) you may well have a large 0 Hz component which is larger than your fundamental or harmonics and (b) depending on the nature of the sound you are trying to analyse, the fundamental may be smaller in magnitude than the harmonics (it may even be missing completely)

I suggest you do the following:

  • apply a suitable window function prior to the FFT - this should make your peaks better defined and should reduce the artefacts at 0 Hz and just above

  • start your search at an appropriate bin rather than 0, e.g. if the minimum fundamental frequency you are interested in is say 50 Hz then start at the corresponding bin for 50 Hz rather than at 0

  • add a debug option to display the spectrum graphically - this visual debugging aid will help greatly when you are wondering why your results do not make sense

  • if what you are really trying to measure is pitch rather than fundamental frequency, then read up on pitch detection algorithms, e.g. Harmonic Product Spectrum - this will work a lot better than the naïve approach of trying to identify a fundamental (whose frequency will not be the same as the pitch in the general case)

Upvotes: 1

Related Questions