2017-04-18 4 views
1

SDL2とFFTW3を使用してC++で音楽ビジュアライザを作成しようとしています。 私の目的は、.wavオーディオファイルをロードし、同時にオーディオを再生し、SDL2コールバック機能を使用してリアルタイム高速フーリエ変換を実行することです。 周波数スペクトルデータを取得して、グラフィカルビジュアライザーを後で実装できるようにしたいと考えています。SDL2オーディオストリームデータでリアルタイムFFTを実行するにはどうすればいいですか

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

Iは、内蔵のnumpyの-FFT機能、それを送信する前に、numpyの配列に.WAVデータを解凍するためにnumpyのを使用しますが、私はそのSDLストリームデータをどうするかについて無知です私はここにいる。

答えて

2

あなたが望むのは短期FFTです。ストリームからサンプルのバッファを収集し、FFTを実行する前にサンプルにウィンドウ関数を適用します。別のバッファを収集し、最初のバッファからいくつかのサンプルを保持して、新しいサンプルを追加します。すべてのデータが処理されるまで繰り返します。

入力データが実数であるため、FFTは対称であるため、最初のN/2 + 1複素出力ビンのみが必要です。これらは、d。 〜Fs/2になる。彼らの大きさとプロットを取る。 FFTごとに繰り返します。

+0

ほぼ正しいです。説明した解決策の問題は、窓関数の適用が破壊的であることである。 「最初のバッファからいくつかのサンプルを保持する」と言うと、窓付きのサンプルを保持します。実際、小さなオーバーラップでは、ウィンドウ関数がほぼゼロである各ウィンドウの端に、ほとんどのフィルタリングされた部分を正確に保持します。重複するウィンドウを使用する場合は、サンプルをコピーするときにウィンドウ関数を適用することをお勧めします。私。 'auto * windowed = buffer * windowFunction'の代わりに' buffer * = windowFunction'を使います。 – MSalters

+0

あなたはもちろんそうです。私は私のiPadのキーボードでこれを入力しようとしていたので、詳細を提供するのはかなり不透明でした。それでも、その重要な詳細。ありがとう。 – sizzzzlerz

関連する問題