如何对 SDL2 音频流数据执行实时 FFT
How can I perform a realtime FFT on SDL2 audio stream data
我正在尝试使用 SDL2 和 FFTW3 在 C++ 中创建音乐可视化工具。
我的目标是加载一个 .wav 音频文件,然后同时播放音频并使用 SDL2 回调函数执行实时快速傅立叶变换。
我想获取频谱数据,以便日后实现图形可视化工具。
我遵循了有关加载 .wav 和使用回调函数播放音频的 SDL YouTube 指南,但我不明白如何对此数据执行 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 流数据这里。
你想要的是短期FFT。您从流中收集样本缓冲区,并在执行 FFT 之前对样本应用 window 函数。然后您收集另一个缓冲区,保留第一个缓冲区中的一些样本并附加新样本。重复直到处理完所有数据。
由于您的输入数据是真实的,FFT 是对称的,因此您只需要前 N/2+1 个复数输出箱。这些代表来自 d.c 的频率。至 Fs/2。考虑它们的大小并绘制。对每个 FFT 重复。
我正在尝试使用 SDL2 和 FFTW3 在 C++ 中创建音乐可视化工具。 我的目标是加载一个 .wav 音频文件,然后同时播放音频并使用 SDL2 回调函数执行实时快速傅立叶变换。 我想获取频谱数据,以便日后实现图形可视化工具。
我遵循了有关加载 .wav 和使用回调函数播放音频的 SDL YouTube 指南,但我不明白如何对此数据执行 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 流数据这里。
你想要的是短期FFT。您从流中收集样本缓冲区,并在执行 FFT 之前对样本应用 window 函数。然后您收集另一个缓冲区,保留第一个缓冲区中的一些样本并附加新样本。重复直到处理完所有数据。
由于您的输入数据是真实的,FFT 是对称的,因此您只需要前 N/2+1 个复数输出箱。这些代表来自 d.c 的频率。至 Fs/2。考虑它们的大小并绘制。对每个 FFT 重复。