shairport-sync/FFTConvolver/AudioFFT.h

177 lines
5.6 KiB
C++
Executable File

// ==================================================================================
// Copyright (c) 2016 HiFi-LoFi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ==================================================================================
#ifndef _AUDIOFFT_H
#define _AUDIOFFT_H
/**
* AudioFFT provides real-to-complex/complex-to-real FFT routines.
*
* Features:
*
* - Real-complex FFT and complex-real inverse FFT for power-of-2-sized real data.
*
* - Uniform interface to different FFT implementations (currently Ooura, FFTW3 and Apple Accelerate).
*
* - Complex data is handled in "split-complex" format, i.e. there are separate
* arrays for the real and imaginary parts which can be useful for SIMD optimizations
* (split-complex arrays have to be of length (size/2+1) representing bins from DC
* to Nyquist frequency).
*
* - Output is "ready to use" (all scaling etc. is already handled internally).
*
* - No allocations/deallocations after the initialization which makes it usable
* for real-time audio applications (that's what I wrote it for and using it).
*
*
* How to use it in your project:
*
* - Add the .h and .cpp file to your project - that's all.
*
* - To get extra speed, you can link FFTW3 to your project and define
* AUDIOFFT_FFTW3 (however, please check whether your project suits the
* according license).
*
* - To get the best speed on Apple platforms, you can link the Apple
* Accelerate framework to your project and define
* AUDIOFFT_APPLE_ACCELERATE (however, please check whether your
* project suits the according license).
*
*
* Remarks:
*
* - AudioFFT is not intended to be the fastest FFT, but to be a fast-enough
* FFT suitable for most audio applications.
*
* - AudioFFT uses the quite liberal MIT license.
*
*
* Example usage:
* @code
* #include "AudioFFT.h"
*
* void Example()
* {
* const size_t fftSize = 1024; // Needs to be power of 2!
*
* std::vector<float> input(fftSize, 0.0f);
* std::vector<float> re(audiofft::AudioFFT::ComplexSize(fftSize));
* std::vector<float> im(audiofft::AudioFFT::ComplexSize(fftSize));
* std::vector<float> output(fftSize);
*
* audiofft::AudioFFT fft;
* fft.init(1024);
* fft.fft(input.data(), re.data(), im.data());
* fft.ifft(output.data(), re.data(), im.data());
* }
* @endcode
*/
#include <cstddef>
#include <memory>
namespace audiofft
{
namespace details
{
class AudioFFTImpl
{
public:
AudioFFTImpl() = default;
virtual ~AudioFFTImpl() = default;
virtual void init(size_t size) = 0;
virtual void fft(const float* data, float* re, float* im) = 0;
virtual void ifft(float* data, const float* re, const float* im) = 0;
private:
AudioFFTImpl(const AudioFFTImpl&) = delete;
AudioFFTImpl& operator=(const AudioFFTImpl&) = delete;
};
}
// ======================================================
/**
* @class AudioFFT
* @brief Performs 1D FFTs
*/
class AudioFFT
{
public:
/**
* @brief Constructor
*/
AudioFFT();
/**
* @brief Initializes the FFT object
* @param size Size of the real input (must be power 2)
*/
void init(size_t size);
/**
* @brief Performs the forward FFT
* @param data The real input data (has to be of the length as specified in init())
* @param re The real part of the complex output (has to be of length as returned by ComplexSize())
* @param im The imaginary part of the complex output (has to be of length as returned by ComplexSize())
*/
void fft(const float* data, float* re, float* im);
/**
* @brief Performs the inverse FFT
* @param data The real output data (has to be of the length as specified in init())
* @param re The real part of the complex input (has to be of length as returned by ComplexSize())
* @param im The imaginary part of the complex input (has to be of length as returned by ComplexSize())
*/
void ifft(float* data, const float* re, const float* im);
/**
* @brief Calculates the necessary size of the real/imaginary complex arrays
* @param size The size of the real data
* @return The size of the real/imaginary complex arrays
*/
static size_t ComplexSize(size_t size);
private:
std::unique_ptr<details::AudioFFTImpl> _impl;
AudioFFT(const AudioFFT&) = delete;
AudioFFT& operator=(const AudioFFT&) = delete;
};
/**
* @deprecated
* @brief Let's keep an AudioFFTBase type around for now because it has been here already in the 1st version in order to avoid breaking existing code.
*/
typedef AudioFFT AudioFFTBase;
} // End of namespace
#endif // Header guard