83 lines
3.1 KiB
C++
83 lines
3.1 KiB
C++
#include <VulcanoLE/Audio/FFT.h>
|
|
#include <VUtils/Logging.h>
|
|
#include <cmath>
|
|
#include <VUtils/Math.h>
|
|
|
|
#define LIMIT 100
|
|
|
|
double FFT::limit = LIMIT;
|
|
void FFT::process(stereoSample *frame, double scale) {
|
|
std::unique_lock<std::mutex> lck(m_mtx);
|
|
if (prepareInput(frame, BUFFER_SIZE, scale)) {
|
|
for (int i = 0; i < BUFFER_SIZE; ++i) {
|
|
m_sample->leftChannel[i] = 0;
|
|
m_sample->rightChannel[i] = 0;
|
|
}
|
|
// reset limit :D
|
|
times++;
|
|
if (times > 100 && limit != LIMIT) {
|
|
DBG("RESET OVERSHOT TO 100")
|
|
limit = LIMIT;
|
|
times = 0;
|
|
}
|
|
return;
|
|
}
|
|
m_fftwPlanRight = fftw_plan_dft_1d(BUFFER_SIZE, m_fftwInputRight, m_fftwOutputRight, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
m_fftwPlanLeft = fftw_plan_dft_1d(BUFFER_SIZE, m_fftwInputLeft, m_fftwOutputLeft, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
fftw_execute(m_fftwPlanLeft);
|
|
fftw_execute(m_fftwPlanRight);
|
|
for (int i = 0; i < BUFFER_SIZE; ++i) {
|
|
double left = std::sqrt(
|
|
m_fftwOutputLeft[i][0] * m_fftwOutputLeft[i][0] + m_fftwOutputLeft[i][1] * m_fftwOutputLeft[i][1]);
|
|
double right = std::sqrt(
|
|
m_fftwOutputRight[i][0] * m_fftwOutputRight[i][0] + m_fftwOutputRight[i][1] * m_fftwOutputRight[i][1]);
|
|
m_sample->leftChannel[i] = valueToAmp(left);
|
|
m_sample->rightChannel[i] = valueToAmp(right);
|
|
}
|
|
fftw_destroy_plan(m_fftwPlanRight);
|
|
fftw_destroy_plan(m_fftwPlanLeft);
|
|
}
|
|
|
|
// return vector of floats!
|
|
outputSample *FFT::getData() {
|
|
std::unique_lock<std::mutex> lck(m_mtx);
|
|
return m_sample;
|
|
}
|
|
|
|
bool FFT::prepareInput(stereoSample *buffer, uint32_t sampleSize, double scale) {
|
|
bool is_silent = true;
|
|
for (size_t i = 0; i < sampleSize; ++i) {
|
|
m_fftwInputLeft[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i];
|
|
m_fftwInputRight[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i];
|
|
if (is_silent && (m_fftwInputLeft[i][0] != 0 || m_fftwInputRight[i][0] != 0)) is_silent = false;
|
|
}
|
|
return is_silent;
|
|
}
|
|
|
|
FFT::FFT() {
|
|
m_fftwResults = (static_cast<size_t>(BUFFER_SIZE) / 2.0) + 1;
|
|
m_fftwInputLeft = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex) * BUFFER_SIZE));
|
|
m_fftwInputRight = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex) * BUFFER_SIZE));
|
|
m_fftwOutputLeft = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex) * BUFFER_SIZE));
|
|
m_fftwOutputRight = static_cast<fftw_complex *>(fftw_malloc(sizeof(fftw_complex) * BUFFER_SIZE));
|
|
for (int i = 0; i < BUFFER_SIZE; ++i) {
|
|
hannWindow[i] = 0.54 - 0.46 * std::cos(2 * M_PI * i / BUFFER_SIZE);
|
|
}
|
|
}
|
|
FFT::~FFT() {
|
|
delete m_sample;
|
|
fftw_free(m_fftwInputLeft);
|
|
fftw_free(m_fftwInputRight);
|
|
fftw_free(m_fftwOutputLeft);
|
|
fftw_free(m_fftwOutputRight);
|
|
}
|
|
double FFT::valueToAmp(double value) {
|
|
if (value > limit) {
|
|
double newLimit = std::floor(value) + 11;
|
|
DBG("OVERSHOT %.2f: %.4f -> %.4f", limit, value, newLimit)
|
|
limit = newLimit;
|
|
}
|
|
return VUtils::Math::clamp(value, 0, limit) / limit * 255;
|
|
}
|
|
|