How can I perform a realtime FFT on SDL2 audio stream data

I am trying to create a music visualiser in C++ using SDL2 and FFTW3. My aim is to load a .wav audio file and then simultaneously play the audio and perform a realtime Fast Fourier Transform using an SDL2 Callback function. I want to get the frequency spectrum data so that I can implement the graphical visualiser at a later date.

I followed an SDL YouTube guide on loading the .wav and playing the audio using the callback function, but I don't understand how to perform the FFT on this data. I followed yet another guide on using FFTW and SDL with C to produce a similar effect but I'm still unsure how to actually implement it.

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

From previous experience I used NumPy to unpack .wav data into a NumPy array, before sending it the built-in NumPy-FFT function, but I'm clueless on what to do with the SDL stream data that I have here.


What you want is the short term FFT. You collect a buffer of samples from your stream and apply a window function to the samples before performing the FFT. You then collect another buffer, keeping some samples from the first buffer and appending new samples. Repeat until all the data has been processed.

Since your input data is real, the FFT is symmetric, hence you only want the first N/2+1 complex output bins. These represent frequencies from dc to Fs/2. Take their magnitudes and plot. Repeat for each FFT.

链接地址: http://www.djcxy.com/p/33828.html

上一篇: Python中的时间音频处理

下一篇: 如何对SDL2音频流数据执行实时FFT?