【问题标题】:How can I perform a realtime FFT on SDL2 audio stream data如何对 SDL2 音频流数据执行实时 FFT
【发布时间】:2017-09-14 17:26:41
【问题描述】:

我正在尝试使用 SDL2 和 FFTW3 在 C++ 中创建音乐可视化器。 我的目标是加载一个 .wav 音频文件,然后同时播放音频并使用 SDL2 回调函数执行实时快速傅立叶变换。 我想获取频谱数据,以便以后实现图形可视化。

我按照 SDL YouTube 指南加载 .wav 并使用回调函数播放音频,但我不明白如何对这些数据执行 FFT。我按照另一个指南使用 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 流数据。

【问题讨论】:

    标签: c++ sdl signal-processing wav fftw


    【解决方案1】:

    您想要的是短期 FFT。您从流中收集样本缓冲区,并在执行 FFT 之前将窗口函数应用于样本。然后收集另一个缓冲区,从第一个缓冲区中保留一些样本并添加新样本。重复直到处理完所有数据。

    由于您的输入数据是真实的,因此 FFT 是对称的,因此您只需要前 N/2+1 个复数输出箱。这些代表来自直流的频率。到 Fs/2。取它们的大小和情节。对每个 FFT 重复。

    【讨论】:

    • 几乎正确。所描述的解决方案的问题是窗口函数的应用是破坏性的。当您说“从第一个缓冲区保留一些样本”时,您将保留窗口样本。事实上,如果重叠很小,您可以在每个窗口的边缘准确地保留 过滤部分,其中窗口函数几乎为零。如果您使用重叠窗口,最好在复制样本时应用窗口功能。 IE。 auto windowed = buffer * windowFunction 而不是 buffer *= windowFunction
    • 你是对的,当然。当我试图在我的 iPad 键盘上输入时,我在提供细节方面非常不透明。尽管如此,它仍然是一个重要的细节。谢谢。
    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    • 2019-10-28
    相关资源
    最近更新 更多