2017-04-18 4 views
1

J'essaie de créer un visualiseur de musique en C++ en utilisant SDL2 et FFTW3. Mon but est de charger un fichier audio .wav, puis de lire simultanément l'audio et d'effectuer une transformation de Fourier rapide en temps réel à l'aide d'une fonction de rappel SDL2. Je veux obtenir les données de spectre de fréquence afin que je puisse implémenter le visualiseur graphique à une date ultérieure.Comment puis-je effectuer une FFT en temps réel sur des données de flux audio SDL2

J'ai suivi un guide YouTube SDL sur le chargement du .wav et de jouer l'audio en utilisant la fonction de rappel, mais je ne comprends pas comment effectuer la FFT sur ces données. J'ai suivi un autre guide sur l'utilisation de FFTW et SDL avec C pour produire un effet similaire mais je ne sais toujours pas comment l'implémenter.

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

De l'expérience précédente je NumPy pour décompresser .wav données dans un tableau NumPy, avant de l'envoyer à la fonction intégrée NumPy-FFT, mais je ne suis aucune idée sur ce qu'il faut faire avec les données de flux SDL qui J'ai ici.

Répondre

2

Ce que vous voulez, c'est la FFT à court terme. Vous collectez un tampon d'échantillons à partir de votre flux et appliquez une fonction de fenêtre aux échantillons avant d'effectuer la FFT. Vous collectez ensuite un autre tampon, en conservant quelques échantillons du premier tampon et en ajoutant de nouveaux échantillons. Répétez jusqu'à ce que toutes les données ont été traitées.

Depuis vos données d'entrée est réelle, la FFT est symétrique, donc vous ne souhaitez que les N/2 + 1 bacs de sortie complexes. Ceux-ci représentent les fréquences de d.c. à Fs/2. Prenez leur grandeur et complot. Répétez pour chaque FFT.

+0

Presque correct. Le problème avec la solution telle que décrite est que l'application de la fonction de fenêtre est destructive. Lorsque vous dites "conserver des échantillons du premier tampon", vous conserverez des échantillons fenêtrés. En fait, avec de petits chevauchements, vous gardez exactement les parties les plus filtrées au bord de chaque fenêtre, où la fonction de la fenêtre est presque nulle. Si vous utilisez des fenêtres qui se chevauchent, il est préférable d'appliquer la fonction de fenêtre lors de la copie des échantillons. C'est à dire. 'auto windowed = buffer * windowFunction' au lieu de' buffer * = windowFunction'. – MSalters

+0

Vous avez raison, bien sûr. J'étais assez opaque en fournissant des détails que j'essayais d'entrer ceci sur mon clavier d'iPad. Pourtant, c'est un détail important. Merci. – sizzzzlerz