Как получить амплитуды частоты из звука PCM? - PullRequest
0 голосов
/ 26 марта 2020

Итак, я пытаюсь получить значения частоты дБ от 0 Гц до 22 кГц для 1-секундной записи ИКМ. Я получаю сырой PCM от записи микрофона PulseAudio Simple API и пытаюсь сделать FFT на этом с помощью FFTW. Я поэкспериментировал с настройками FFTW взад и вперед (я тоже пробовал fftw_plan_dft_r2c_1d), но мне все еще кажется, что в выводе FFTW я получаю ненужные данные. Кажется, я не могу найти никакой корреляции между выходным сигналом и частотами, которые я записываю.

Я попытался вывести PCM в файл и воспроизвести его с VL C, и он успешно воспроизводился - так что-то что-то не так с моим FFT.

Вот мой код:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <math.h>

#include <pulse/simple.h>
#include <pulse/error.h>

#include <fftw3.h>

static ssize_t loop_write(uint8_t *data, size_t size) {
    fftw_complex *in, *out;
    fftw_plan p;
    in = (fftw_complex*) malloc(sizeof(fftw_complex) * size);
    out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * size);

    for (int i = 0; i < size; i++) {
        in[i][0] = data[i * 8];
        in[i][1] = (float) 0;
    }

    p = fftw_plan_dft_1d(size, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    fftw_execute(p);

    double max = 0;
    int maxi = 0;
    for (int i = 1; i < size; i++) {
        double calc = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]);
        if (calc > max) {
            max = calc;
            maxi = i;
        }
    }
    printf("%d: %f\n", maxi, max);

    fftw_destroy_plan(p);
    fftw_free(in); fftw_free(out);
}

int main(int argc, char*argv[]) {
    static const pa_sample_spec ss = {
        .format = PA_SAMPLE_S16LE,
        .rate = 44100,
        .channels = 1
    };
    pa_simple *s = NULL;
    int error;

    if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
        fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
        goto finish;
    }

    uint8_t buf[88200];
    if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
        fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
        goto finish;
    }

    loop_write(buf, sizeof(buf) / 8);
finish:
    if (s)
        pa_simple_free(s);
    return 0;
}

Есть идеи, что я делаю неправильно? Как я могу получить значения частоты?

...