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);
}
}
從我使用NumPy的爲.wav數據解壓到一個NumPy的陣列以往的經驗,在發送前內置NumPy的-FFT功能,但我什麼與SDL流數據做是無能我在這裏。
幾乎正確。所描述的解決方案的問題是窗口函數的應用是破壞性的。當你說「保留第一個緩衝區的一些樣本」時,你會保留窗口樣本。事實上,在重疊較小的情況下,您可以將每個窗口邊緣的最大濾波部分保留在窗口函數幾乎爲零的位置。如果使用重疊窗口,最好在複製樣本時應用窗口函數。即'auto windowed = buffer * windowFunction'而不是'buffer * = windowFunction'。 – MSalters
當然你是對的。我在提供細節時非常不透明,因爲我試圖在iPad鍵盤上輸入此信息。不過,它是一個重要的細節。謝謝。 – sizzzzlerz