#pragma once #include #include #include class FFT; /** * Our wrapper api uses std::complex, so we don't need to expose kiss_fft_cpx * outside. Our implementation assumes the two are equivalent, and that a * reinterpret_cast can bridge them. */ using cpx = std::complex; template class FFTData { public: friend FFT; FFTData(int numBins); ~FFTData(); T get(int bin) const; void set(int bin, T value); int size() const { return (int) buffer.size(); } T * data() { return buffer.data(); } float getAbs(int bin) const { return std::abs(buffer[bin]); } static int _count; private: std::vector buffer; /** * we store this without type so that clients don't need * to pull in the kiss_fft headers. It's mutable so it can * be lazy created by FFT functions. * Note that the cfg has a "direction" baked into it. For * now we assume that all FFT with complex input will be inverse FFTs. */ mutable void * kiss_cfg = 0; }; using FFTDataReal = FFTData; using FFTDataCpx = FFTData; template int FFTData::_count = 0; template inline FFTData::FFTData(int numBins) : buffer(numBins) { ++_count; } template inline FFTData::~FFTData() { // We need to manually delete the cfg, since only "we" know // what type it is. if (kiss_cfg) { free(kiss_cfg); } --_count; } template inline T FFTData::get(int index) const { assert(index < (int) buffer.size() && index >= 0); return buffer[index]; } template inline void FFTData::set(int index, T value) { assert(index < (int) buffer.size() && index >= 0); buffer[index] = value; }