Как я могу выполнить БПФ в реальном времени на данных аудиопотока SDL2

Я пытаюсь создать визуализатор музыки в C++, используя SDL2 и FFTW3. Моя цель - загрузить аудиофайл.wav, а затем одновременно воспроизвести аудио и выполнить быстрое преобразование Фурье в реальном времени, используя функцию обратного вызова SDL2. Я хочу получить данные о частотном спектре, чтобы позже я смог реализовать графический визуализатор.

Я следовал руководству SDL YouTube по загрузке.wav и воспроизведению аудио с помощью функции обратного вызова, но я не понимаю, как выполнить БПФ для этих данных. Я следовал еще одному руководству по использованию FFTW и SDL с C для получения аналогичного эффекта, но я все еще не уверен, как на самом деле реализовать его.

Uint8* sampData;
SDL_AudioSpec wavSpec;
Uint8* wavStart;
Uint32 wavLength;
SDL_AudioDeviceID aDevice;

struct AudioData {
    Uint8* filePosition;
    Uint32 fileLength;
};

void PlayAudioCallback(void* userData, Uint8* stream, int streamLength) {
    AudioData* audio = (AudioData*)userData;
    sampData = new Uint8;

    if (audio->fileLength == 0) {
        return;
    }

    Uint32 length = (Uint32)streamLength;
    length = (length > audio->fileLength ? audio->fileLength : length);

    SDL_memcpy(stream, audio->filePosition, length);

    // HERE is where i'd like to implement the FFT on 'stream' data 
    // but i don't know how to implement this using FFTW

    audio->filePosition += length;
    audio->fileLength -= length;
}

int main() {
    SDL_Init(SDL_INIT_AUDIO);

    // Load .wav file
    if (SDL_LoadWAV(FILE_PATH, &wavSpec, &wavStart, &wavLength) == NULL) {
        cerr << "Couldnt load file: " << FILE_PATH << endl;
        getchar();
    }
    cout << "Loaded " << FILE_PATH << endl;

    AudioData audio;
    audio.filePosition = wavStart;
    audio.fileLength = wavLength;

    wavSpec.callback = PlayAudioCallback;
    wavSpec.userdata = &audio;

    // Open audio playback endpoint
    aDevice = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE);
    if (aDevice == 0) {
        cerr << "Audio Device connection failed: " << SDL_GetError() << endl;
        getchar();
    }
    // Play audio on playback endpoint
    SDL_PauseAudioDevice(aDevice, 0);

    // Do nothing while there's still data to be played
    while (audio.fileLength > 0) {
        SDL_Delay(100);
    }
}

Из предыдущего опыта я использовал NumPy для распаковки данных.wav в массив NumPy, прежде чем отправлять ему встроенную функцию NumPy-FFT, но я не знаю, что делать с данными потока SDL, которые у меня есть.

1 ответ

Решение

То, что вы хотите, это краткосрочный БПФ. Вы собираете буфер сэмплов из вашего потока и применяете оконную функцию к сэмплам перед выполнением БПФ. Затем вы собираете другой буфер, сохраняя некоторые сэмплы из первого буфера и добавляя новые сэмплы. Повторяйте, пока все данные не будут обработаны.

Поскольку ваши входные данные реальны, БПФ является симметричным, поэтому вам нужны только первые N/2+1 комплексные выходные лотки. Они представляют частоты от постоянного тока до Fs/2. Возьмите их величины и заговор. Повторите для каждого БПФ.

Другие вопросы по тегам