mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-04 20:55:48 +01:00
update qm-dsp library
This commit is contained in:
parent
2a27cc4758
commit
f68d2e06bc
100 changed files with 58968 additions and 55091 deletions
|
|
@ -4,178 +4,199 @@
|
|||
QM DSP Library
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
This file is based on Don Cross's public domain FFT implementation.
|
||||
*/
|
||||
|
||||
#include "FFT.h"
|
||||
|
||||
#include "maths/MathUtilities.h"
|
||||
|
||||
#include "kiss_fft.h"
|
||||
#include "kiss_fftr.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
FFT::FFT(unsigned int n) :
|
||||
m_n(n),
|
||||
m_private(0)
|
||||
#include <stdexcept>
|
||||
|
||||
class FFT::D
|
||||
{
|
||||
if( !MathUtilities::isPowerOfTwo(m_n) )
|
||||
{
|
||||
std::cerr << "ERROR: FFT: Non-power-of-two FFT size "
|
||||
<< m_n << " not supported in this implementation"
|
||||
<< std::endl;
|
||||
return;
|
||||
public:
|
||||
D(int n) : m_n(n) {
|
||||
m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL);
|
||||
m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL);
|
||||
m_kin = new kiss_fft_cpx[m_n];
|
||||
m_kout = new kiss_fft_cpx[m_n];
|
||||
}
|
||||
|
||||
~D() {
|
||||
kiss_fft_free(m_planf);
|
||||
kiss_fft_free(m_plani);
|
||||
delete[] m_kin;
|
||||
delete[] m_kout;
|
||||
}
|
||||
|
||||
void process(bool inverse,
|
||||
const double *ri,
|
||||
const double *ii,
|
||||
double *ro,
|
||||
double *io) {
|
||||
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
m_kin[i].r = ri[i];
|
||||
m_kin[i].i = (ii ? ii[i] : 0.0);
|
||||
}
|
||||
|
||||
if (!inverse) {
|
||||
|
||||
kiss_fft(m_planf, m_kin, m_kout);
|
||||
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
ro[i] = m_kout[i].r;
|
||||
io[i] = m_kout[i].i;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
kiss_fft(m_plani, m_kin, m_kout);
|
||||
|
||||
double scale = 1.0 / m_n;
|
||||
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
ro[i] = m_kout[i].r * scale;
|
||||
io[i] = m_kout[i].i * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_n;
|
||||
kiss_fft_cfg m_planf;
|
||||
kiss_fft_cfg m_plani;
|
||||
kiss_fft_cpx *m_kin;
|
||||
kiss_fft_cpx *m_kout;
|
||||
};
|
||||
|
||||
FFT::FFT(int n) :
|
||||
m_d(new D(n))
|
||||
{
|
||||
}
|
||||
|
||||
FFT::~FFT()
|
||||
{
|
||||
|
||||
delete m_d;
|
||||
}
|
||||
|
||||
FFTReal::FFTReal(unsigned int n) :
|
||||
m_n(n),
|
||||
m_private_real(0)
|
||||
void
|
||||
FFT::process(bool inverse,
|
||||
const double *p_lpRealIn, const double *p_lpImagIn,
|
||||
double *p_lpRealOut, double *p_lpImagOut)
|
||||
{
|
||||
m_d->process(inverse,
|
||||
p_lpRealIn, p_lpImagIn,
|
||||
p_lpRealOut, p_lpImagOut);
|
||||
}
|
||||
|
||||
class FFTReal::D
|
||||
{
|
||||
public:
|
||||
D(int n) : m_n(n) {
|
||||
if (n % 2) {
|
||||
throw std::invalid_argument
|
||||
("nsamples must be even in FFTReal constructor");
|
||||
}
|
||||
m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL);
|
||||
m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL);
|
||||
m_c = new kiss_fft_cpx[m_n];
|
||||
}
|
||||
|
||||
~D() {
|
||||
kiss_fftr_free(m_planf);
|
||||
kiss_fftr_free(m_plani);
|
||||
delete[] m_c;
|
||||
}
|
||||
|
||||
void forward(const double *ri, double *ro, double *io) {
|
||||
|
||||
kiss_fftr(m_planf, ri, m_c);
|
||||
|
||||
for (int i = 0; i <= m_n/2; ++i) {
|
||||
ro[i] = m_c[i].r;
|
||||
io[i] = m_c[i].i;
|
||||
}
|
||||
|
||||
for (int i = 0; i + 1 < m_n/2; ++i) {
|
||||
ro[m_n - i - 1] = ro[i + 1];
|
||||
io[m_n - i - 1] = -io[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
void forwardMagnitude(const double *ri, double *mo) {
|
||||
|
||||
double *io = new double[m_n];
|
||||
|
||||
forward(ri, mo, io);
|
||||
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
mo[i] = sqrt(mo[i] * mo[i] + io[i] * io[i]);
|
||||
}
|
||||
|
||||
delete[] io;
|
||||
}
|
||||
|
||||
void inverse(const double *ri, const double *ii, double *ro) {
|
||||
|
||||
// kiss_fftr.h says
|
||||
// "input freqdata has nfft/2+1 complex points"
|
||||
|
||||
for (int i = 0; i < m_n/2 + 1; ++i) {
|
||||
m_c[i].r = ri[i];
|
||||
m_c[i].i = ii[i];
|
||||
}
|
||||
|
||||
kiss_fftri(m_plani, m_c, ro);
|
||||
|
||||
double scale = 1.0 / m_n;
|
||||
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
ro[i] *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_n;
|
||||
kiss_fftr_cfg m_planf;
|
||||
kiss_fftr_cfg m_plani;
|
||||
kiss_fft_cpx *m_c;
|
||||
};
|
||||
|
||||
FFTReal::FFTReal(int n) :
|
||||
m_d(new D(n))
|
||||
{
|
||||
m_private_real = new FFT(m_n);
|
||||
}
|
||||
|
||||
FFTReal::~FFTReal()
|
||||
{
|
||||
delete (FFT *)m_private_real;
|
||||
delete m_d;
|
||||
}
|
||||
|
||||
void
|
||||
FFTReal::process(bool inverse,
|
||||
const double *realIn,
|
||||
double *realOut, double *imagOut)
|
||||
FFTReal::forward(const double *ri, double *ro, double *io)
|
||||
{
|
||||
((FFT *)m_private_real)->process(inverse, realIn, 0, realOut, imagOut);
|
||||
}
|
||||
|
||||
static unsigned int numberOfBitsNeeded(unsigned int p_nSamples)
|
||||
{
|
||||
int i;
|
||||
|
||||
if( p_nSamples < 2 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( i=0; ; i++ )
|
||||
{
|
||||
if( p_nSamples & (1 << i) ) return i;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int reverseBits(unsigned int p_nIndex, unsigned int p_nBits)
|
||||
{
|
||||
unsigned int i, rev;
|
||||
|
||||
for(i=rev=0; i < p_nBits; i++)
|
||||
{
|
||||
rev = (rev << 1) | (p_nIndex & 1);
|
||||
p_nIndex >>= 1;
|
||||
}
|
||||
|
||||
return rev;
|
||||
m_d->forward(ri, ro, io);
|
||||
}
|
||||
|
||||
void
|
||||
FFT::process(bool p_bInverseTransform,
|
||||
const double *p_lpRealIn, const double *p_lpImagIn,
|
||||
double *p_lpRealOut, double *p_lpImagOut)
|
||||
FFTReal::forwardMagnitude(const double *ri, double *mo)
|
||||
{
|
||||
if (!p_lpRealIn || !p_lpRealOut || !p_lpImagOut) return;
|
||||
|
||||
// std::cerr << "FFT::process(" << m_n << "," << p_bInverseTransform << ")" << std::endl;
|
||||
|
||||
unsigned int NumBits;
|
||||
unsigned int i, j, k, n;
|
||||
unsigned int BlockSize, BlockEnd;
|
||||
|
||||
double angle_numerator = 2.0 * M_PI;
|
||||
double tr, ti;
|
||||
|
||||
if( !MathUtilities::isPowerOfTwo(m_n) )
|
||||
{
|
||||
std::cerr << "ERROR: FFT::process: Non-power-of-two FFT size "
|
||||
<< m_n << " not supported in this implementation"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( p_bInverseTransform ) angle_numerator = -angle_numerator;
|
||||
|
||||
NumBits = numberOfBitsNeeded ( m_n );
|
||||
|
||||
|
||||
for( i=0; i < m_n; i++ )
|
||||
{
|
||||
j = reverseBits ( i, NumBits );
|
||||
p_lpRealOut[j] = p_lpRealIn[i];
|
||||
p_lpImagOut[j] = (p_lpImagIn == 0) ? 0.0 : p_lpImagIn[i];
|
||||
}
|
||||
|
||||
|
||||
BlockEnd = 1;
|
||||
for( BlockSize = 2; BlockSize <= m_n; BlockSize <<= 1 )
|
||||
{
|
||||
double delta_angle = angle_numerator / (double)BlockSize;
|
||||
double sm2 = -sin ( -2 * delta_angle );
|
||||
double sm1 = -sin ( -delta_angle );
|
||||
double cm2 = cos ( -2 * delta_angle );
|
||||
double cm1 = cos ( -delta_angle );
|
||||
double w = 2 * cm1;
|
||||
double ar[3], ai[3];
|
||||
|
||||
for( i=0; i < m_n; i += BlockSize )
|
||||
{
|
||||
|
||||
ar[2] = cm2;
|
||||
ar[1] = cm1;
|
||||
|
||||
ai[2] = sm2;
|
||||
ai[1] = sm1;
|
||||
|
||||
for ( j=i, n=0; n < BlockEnd; j++, n++ )
|
||||
{
|
||||
|
||||
ar[0] = w*ar[1] - ar[2];
|
||||
ar[2] = ar[1];
|
||||
ar[1] = ar[0];
|
||||
|
||||
ai[0] = w*ai[1] - ai[2];
|
||||
ai[2] = ai[1];
|
||||
ai[1] = ai[0];
|
||||
|
||||
k = j + BlockEnd;
|
||||
tr = ar[0]*p_lpRealOut[k] - ai[0]*p_lpImagOut[k];
|
||||
ti = ar[0]*p_lpImagOut[k] + ai[0]*p_lpRealOut[k];
|
||||
|
||||
p_lpRealOut[k] = p_lpRealOut[j] - tr;
|
||||
p_lpImagOut[k] = p_lpImagOut[j] - ti;
|
||||
|
||||
p_lpRealOut[j] += tr;
|
||||
p_lpImagOut[j] += ti;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BlockEnd = BlockSize;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if( p_bInverseTransform )
|
||||
{
|
||||
double denom = (double)m_n;
|
||||
|
||||
for ( i=0; i < m_n; i++ )
|
||||
{
|
||||
p_lpRealOut[i] /= denom;
|
||||
p_lpImagOut[i] /= denom;
|
||||
}
|
||||
}
|
||||
m_d->forwardMagnitude(ri, mo);
|
||||
}
|
||||
|
||||
void
|
||||
FFTReal::inverse(const double *ri, const double *ii, double *ro)
|
||||
{
|
||||
m_d->inverse(ri, ii, ro);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,34 +9,97 @@
|
|||
#ifndef FFT_H
|
||||
#define FFT_H
|
||||
|
||||
class FFT
|
||||
class FFT
|
||||
{
|
||||
public:
|
||||
FFT(unsigned int nsamples);
|
||||
virtual ~FFT();
|
||||
/**
|
||||
* Construct an FFT object to carry out complex-to-complex
|
||||
* transforms of size nsamples. nsamples does not have to be a
|
||||
* power of two.
|
||||
*/
|
||||
FFT(int nsamples);
|
||||
~FFT();
|
||||
|
||||
/**
|
||||
* Carry out a forward or inverse transform (depending on the
|
||||
* value of inverse) of size nsamples, where nsamples is the value
|
||||
* provided to the constructor above.
|
||||
*
|
||||
* realIn and (where present) imagIn should contain nsamples each,
|
||||
* and realOut and imagOut should point to enough space to receive
|
||||
* nsamples each.
|
||||
*
|
||||
* imagIn may be NULL if the signal is real, but the other
|
||||
* pointers must be valid.
|
||||
*
|
||||
* The inverse transform is scaled by 1/nsamples.
|
||||
*/
|
||||
void process(bool inverse,
|
||||
const double *realIn, const double *imagIn,
|
||||
double *realOut, double *imagOut);
|
||||
|
||||
|
||||
private:
|
||||
unsigned int m_n;
|
||||
void *m_private;
|
||||
class D;
|
||||
D *m_d;
|
||||
};
|
||||
|
||||
class FFTReal
|
||||
{
|
||||
public:
|
||||
FFTReal(unsigned int nsamples);
|
||||
/**
|
||||
* Construct an FFT object to carry out real-to-complex transforms
|
||||
* of size nsamples. nsamples does not have to be a power of two,
|
||||
* but it does have to be even. (Use the complex-complex FFT above
|
||||
* if you need an odd FFT size. This constructor will throw
|
||||
* std::invalid_argument if nsamples is odd.)
|
||||
*/
|
||||
FFTReal(int nsamples);
|
||||
~FFTReal();
|
||||
|
||||
void process(bool inverse,
|
||||
const double *realIn,
|
||||
/**
|
||||
* Carry out a forward real-to-complex transform of size nsamples,
|
||||
* where nsamples is the value provided to the constructor above.
|
||||
*
|
||||
* realIn, realOut, and imagOut must point to (enough space for)
|
||||
* nsamples values. For consistency with the FFT class above, and
|
||||
* compatibility with existing code, the conjugate half of the
|
||||
* output is returned even though it is redundant.
|
||||
*/
|
||||
void forward(const double *realIn,
|
||||
double *realOut, double *imagOut);
|
||||
|
||||
/**
|
||||
* Carry out a forward real-to-complex transform of size nsamples,
|
||||
* where nsamples is the value provided to the constructor
|
||||
* above. Return only the magnitudes of the complex output values.
|
||||
*
|
||||
* realIn and magOut must point to (enough space for) nsamples
|
||||
* values. For consistency with the FFT class above, and
|
||||
* compatibility with existing code, the conjugate half of the
|
||||
* output is returned even though it is redundant.
|
||||
*/
|
||||
void forwardMagnitude(const double *realIn, double *magOut);
|
||||
|
||||
/**
|
||||
* Carry out an inverse real transform (i.e. complex-to-real) of
|
||||
* size nsamples, where nsamples is the value provided to the
|
||||
* constructor above.
|
||||
*
|
||||
* realIn and imagIn should point to at least nsamples/2+1 values;
|
||||
* if more are provided, only the first nsamples/2+1 values of
|
||||
* each will be used (the conjugate half will always be deduced
|
||||
* from the first nsamples/2+1 rather than being read from the
|
||||
* input data). realOut should point to enough space to receive
|
||||
* nsamples values.
|
||||
*
|
||||
* The inverse transform is scaled by 1/nsamples.
|
||||
*/
|
||||
void inverse(const double *realIn, const double *imagIn,
|
||||
double *realOut);
|
||||
|
||||
private:
|
||||
unsigned int m_n;
|
||||
void *m_private_real;
|
||||
};
|
||||
class D;
|
||||
D *m_d;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue