Add IAudioEffect interface and FFTFilter DSP effect using KissFFT

This commit is contained in:
2026-03-21 12:08:16 +08:00
parent dfc948fc89
commit b68cde82b2
4 changed files with 192 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
#include "FFTFilter.h"
#include <cmath>
#include <cstring>
#include "../../third_party/kissfft/kiss_fftr.h"
#include "../../third_party/kissfft/kiss_fft.h"
namespace XCEngine {
namespace Audio {
FFTFilter::FFTFilter()
: m_spectrumData(512, 0.0f)
, m_prevSpectrum(512, 0.0f)
{
InitializeFFT(m_fftSize);
}
FFTFilter::FFTFilter(uint32 fftSize)
: m_fftSize(fftSize)
, m_spectrumData(fftSize / 2, 0.0f)
, m_prevSpectrum(fftSize / 2, 0.0f)
{
InitializeFFT(fftSize);
}
FFTFilter::~FFTFilter() {
if (m_fftConfig) {
kiss_fft_free(static_cast<kiss_fft_cfg>(m_fftConfig));
m_fftConfig = nullptr;
}
if (m_fftrConfig) {
kiss_fftr_free(static_cast<kiss_fftr_cfg>(m_fftrConfig));
m_fftrConfig = nullptr;
}
}
void FFTFilter::ProcessAudio(float* buffer, uint32 sampleCount, uint32 channels) {
if (!m_enabled || buffer == nullptr || sampleCount == 0) {
return;
}
if (channels == 0) {
return;
}
if (sampleCount < m_fftSize) {
return;
}
uint32 binCount = m_fftSize / 2;
if (m_spectrumData.size() != binCount) {
m_spectrumData.resize(binCount);
m_prevSpectrum.resize(binCount);
}
std::vector<float> monoBuffer(m_fftSize, 0.0f);
for (uint32 i = 0; i < m_fftSize; ++i) {
uint32 channelIndex = (channels == 1) ? 0 : (i % channels);
monoBuffer[i] = buffer[i * channels + channelIndex];
}
ComputeFFT(monoBuffer.data(), m_fftSize);
}
void FFTFilter::SetFFTSize(uint32 size) {
if (size == m_fftSize) {
return;
}
m_fftSize = size;
m_spectrumData.resize(size / 2);
m_prevSpectrum.resize(size / 2);
InitializeFFT(size);
}
void FFTFilter::SetSmoothingFactor(float factor) {
m_smoothingFactor = std::max(0.0f, std::min(1.0f, factor));
}
void FFTFilter::InitializeFFT(uint32 size) {
if (m_fftConfig) {
kiss_fft_free(static_cast<kiss_fft_cfg>(m_fftConfig));
}
if (m_fftrConfig) {
kiss_fftr_free(static_cast<kiss_fftr_cfg>(m_fftrConfig));
}
m_fftConfig = kiss_fft_alloc(size, 0, nullptr, nullptr);
m_fftrConfig = kiss_fftr_alloc(size, 0, nullptr, nullptr);
}
void FFTFilter::ComputeFFT(const float* input, uint32 size) {
if (!m_fftrConfig || !input) {
return;
}
kiss_fft_scalar* timedata = new kiss_fft_scalar[size];
kiss_fft_cpx* freqdata = new kiss_fft_cpx[size / 2 + 1];
for (uint32 i = 0; i < size; ++i) {
timedata[i] = input[i];
}
kiss_fftr(static_cast<kiss_fftr_cfg>(m_fftrConfig), timedata, freqdata);
uint32 binCount = size / 2;
for (uint32 i = 0; i < binCount; ++i) {
float magnitude = std::sqrt(freqdata[i].r * freqdata[i].r + freqdata[i].i * freqdata[i].i);
float dbValue = 20.0f * std::log10(magnitude + 1e-10f);
dbValue = std::max(0.0f, std::min(1.0f, (dbValue + 80.0f) / 80.0f));
m_spectrumData[i] = m_spectrumData[i] * m_smoothingFactor + dbValue * (1.0f - m_smoothingFactor);
}
delete[] timedata;
delete[] freqdata;
}
} // namespace Audio
} // namespace XCEngine