annotate dsp/transforms/FFT.cpp @ 298:255e431ae3d4

* Key detector: when returning key strengths, use the peak value of the three underlying chromagram correlations (from 36-bin chromagram) corresponding to each key, instead of the mean. Rationale: This is the same method as used when returning the key value, and it's nice to have the same results in both returned value and plot. The peak performed better than the sum with a simple test set of triads, so it seems reasonable to change the plot to match the key output rather than the other way around. * FFT: kiss_fftr returns only the non-conjugate bins, synthesise the rest rather than leaving them (perhaps dangerously) undefined. Fixes an uninitialised data error in chromagram that could cause garbage results from key detector. * Constant Q: remove precalculated values again, I reckon they're not proving such a good tradeoff.
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 05 Jun 2009 15:12:39 +0000
parents 37bbd2f605f8
children 769da847732b
rev   line source
c@225 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@225 2
c@225 3 /*
c@225 4 QM DSP Library
c@225 5
c@225 6 Centre for Digital Music, Queen Mary, University of London.
c@225 7 This file is based on Don Cross's public domain FFT implementation.
c@225 8 */
c@225 9
c@225 10 #include "FFT.h"
c@280 11
c@280 12 #include "maths/MathUtilities.h"
c@280 13
c@225 14 #include <cmath>
c@225 15
c@280 16 #include <iostream>
c@280 17
c@290 18 //#define USE_BUILTIN_FFT 1
c@225 19
c@289 20 #ifdef USE_BUILTIN_FFT
c@289 21
c@289 22 FFT::FFT(unsigned int n) :
c@289 23 m_n(n),
c@289 24 m_private(0)
c@225 25 {
c@289 26 if( !MathUtilities::isPowerOfTwo(m_n) )
c@289 27 {
c@289 28 std::cerr << "ERROR: FFT: Non-power-of-two FFT size "
c@289 29 << m_n << " not supported in this implementation"
c@289 30 << std::endl;
c@289 31 return;
c@289 32 }
c@225 33 }
c@225 34
c@225 35 FFT::~FFT()
c@225 36 {
c@225 37
c@225 38 }
c@225 39
c@289 40 FFTReal::FFTReal(unsigned int n) :
c@289 41 m_n(n),
c@289 42 m_private(0)
c@225 43 {
c@289 44 m_private = new FFT(m_n);
c@289 45 }
c@225 46
c@289 47 FFTReal::~FFTReal()
c@289 48 {
c@289 49 delete (FFT *)m_private;
c@289 50 }
c@289 51
c@289 52 void
c@289 53 FFTReal::process(bool inverse,
c@289 54 const double *realIn,
c@289 55 double *realOut, double *imagOut)
c@289 56 {
c@289 57 ((FFT *)m_private)->process(inverse, realIn, 0, realOut, imagOut);
c@289 58 }
c@289 59
c@289 60 static unsigned int numberOfBitsNeeded(unsigned int p_nSamples)
c@289 61 {
c@289 62 int i;
c@289 63
c@289 64 if( p_nSamples < 2 )
c@289 65 {
c@289 66 return 0;
c@289 67 }
c@289 68
c@289 69 for ( i=0; ; i++ )
c@289 70 {
c@289 71 if( p_nSamples & (1 << i) ) return i;
c@289 72 }
c@289 73 }
c@289 74
c@289 75 static unsigned int reverseBits(unsigned int p_nIndex, unsigned int p_nBits)
c@289 76 {
c@289 77 unsigned int i, rev;
c@289 78
c@289 79 for(i=rev=0; i < p_nBits; i++)
c@289 80 {
c@289 81 rev = (rev << 1) | (p_nIndex & 1);
c@289 82 p_nIndex >>= 1;
c@289 83 }
c@289 84
c@289 85 return rev;
c@289 86 }
c@289 87
c@289 88 void
c@289 89 FFT::process(bool p_bInverseTransform,
c@289 90 const double *p_lpRealIn, const double *p_lpImagIn,
c@289 91 double *p_lpRealOut, double *p_lpImagOut)
c@289 92 {
c@291 93 if (!p_lpRealIn || !p_lpRealOut || !p_lpImagOut) return;
c@291 94
c@291 95 // std::cerr << "FFT::process(" << m_n << "," << p_bInverseTransform << ")" << std::endl;
c@225 96
c@225 97 unsigned int NumBits;
c@225 98 unsigned int i, j, k, n;
c@225 99 unsigned int BlockSize, BlockEnd;
c@225 100
c@225 101 double angle_numerator = 2.0 * M_PI;
c@225 102 double tr, ti;
c@225 103
c@289 104 if( !MathUtilities::isPowerOfTwo(m_n) )
c@225 105 {
c@280 106 std::cerr << "ERROR: FFT::process: Non-power-of-two FFT size "
c@289 107 << m_n << " not supported in this implementation"
c@280 108 << std::endl;
c@225 109 return;
c@225 110 }
c@225 111
c@225 112 if( p_bInverseTransform ) angle_numerator = -angle_numerator;
c@225 113
c@289 114 NumBits = numberOfBitsNeeded ( m_n );
c@225 115
c@225 116
c@289 117 for( i=0; i < m_n; i++ )
c@225 118 {
c@225 119 j = reverseBits ( i, NumBits );
c@225 120 p_lpRealOut[j] = p_lpRealIn[i];
c@225 121 p_lpImagOut[j] = (p_lpImagIn == 0) ? 0.0 : p_lpImagIn[i];
c@225 122 }
c@225 123
c@225 124
c@225 125 BlockEnd = 1;
c@289 126 for( BlockSize = 2; BlockSize <= m_n; BlockSize <<= 1 )
c@225 127 {
c@225 128 double delta_angle = angle_numerator / (double)BlockSize;
c@225 129 double sm2 = -sin ( -2 * delta_angle );
c@225 130 double sm1 = -sin ( -delta_angle );
c@225 131 double cm2 = cos ( -2 * delta_angle );
c@225 132 double cm1 = cos ( -delta_angle );
c@225 133 double w = 2 * cm1;
c@225 134 double ar[3], ai[3];
c@225 135
c@289 136 for( i=0; i < m_n; i += BlockSize )
c@225 137 {
c@225 138
c@225 139 ar[2] = cm2;
c@225 140 ar[1] = cm1;
c@225 141
c@225 142 ai[2] = sm2;
c@225 143 ai[1] = sm1;
c@225 144
c@225 145 for ( j=i, n=0; n < BlockEnd; j++, n++ )
c@225 146 {
c@225 147
c@225 148 ar[0] = w*ar[1] - ar[2];
c@225 149 ar[2] = ar[1];
c@225 150 ar[1] = ar[0];
c@225 151
c@225 152 ai[0] = w*ai[1] - ai[2];
c@225 153 ai[2] = ai[1];
c@225 154 ai[1] = ai[0];
c@225 155
c@225 156 k = j + BlockEnd;
c@225 157 tr = ar[0]*p_lpRealOut[k] - ai[0]*p_lpImagOut[k];
c@225 158 ti = ar[0]*p_lpImagOut[k] + ai[0]*p_lpRealOut[k];
c@225 159
c@225 160 p_lpRealOut[k] = p_lpRealOut[j] - tr;
c@225 161 p_lpImagOut[k] = p_lpImagOut[j] - ti;
c@225 162
c@225 163 p_lpRealOut[j] += tr;
c@225 164 p_lpImagOut[j] += ti;
c@225 165
c@225 166 }
c@225 167 }
c@225 168
c@225 169 BlockEnd = BlockSize;
c@225 170
c@225 171 }
c@225 172
c@225 173
c@225 174 if( p_bInverseTransform )
c@225 175 {
c@289 176 double denom = (double)m_n;
c@225 177
c@289 178 for ( i=0; i < m_n; i++ )
c@225 179 {
c@225 180 p_lpRealOut[i] /= denom;
c@225 181 p_lpImagOut[i] /= denom;
c@225 182 }
c@225 183 }
c@225 184 }
c@225 185
c@289 186 #else
c@225 187
c@289 188 #include "kissfft/kiss_fft.h"
c@289 189 #include "kissfft/kiss_fftr.h"
c@225 190
c@290 191 struct KissFFTRec {
c@290 192 kiss_fft_cfg forward;
c@290 193 kiss_fft_cfg inverse;
c@290 194 kiss_fft_cpx *in;
c@290 195 kiss_fft_cpx *out;
c@290 196 };
c@290 197
c@290 198 FFT::FFT(unsigned int n) :
c@290 199 m_n(n),
c@290 200 m_private(0)
c@290 201 {
c@290 202 KissFFTRec *rec = new KissFFTRec;
c@290 203 rec->forward = kiss_fft_alloc(m_n, 0, 0, 0);
c@290 204 rec->inverse = kiss_fft_alloc(m_n, 1, 0, 0);
c@290 205 rec->in = new kiss_fft_cpx[m_n];
c@290 206 rec->out = new kiss_fft_cpx[m_n];
c@290 207 m_private = rec;
c@290 208 }
c@290 209
c@290 210 FFT::~FFT()
c@290 211 {
c@290 212 KissFFTRec *rec = (KissFFTRec *)m_private;
c@290 213 kiss_fft_free(rec->forward);
c@290 214 kiss_fft_free(rec->inverse);
c@290 215 delete[] rec->in;
c@290 216 delete[] rec->out;
c@290 217 }
c@290 218
c@290 219 void
c@290 220 FFT::process(bool inverse,
c@290 221 const double *rin, const double *iin,
c@290 222 double *rout, double *iout)
c@290 223 {
c@290 224 KissFFTRec *rec = (KissFFTRec *)m_private;
c@290 225 for (int i = 0; i < m_n; ++i) {
c@290 226 rec->in[i].r = rin[i];
c@290 227 }
c@290 228 if (iin) {
c@290 229 for (int i = 0; i < m_n; ++i) {
c@290 230 rec->in[i].i = iin[i];
c@290 231 }
c@290 232 } else {
c@290 233 for (int i = 0; i < m_n; ++i) {
c@290 234 rec->in[i].i = 0.0;
c@290 235 }
c@290 236 }
c@290 237 if (inverse) {
c@290 238 kiss_fft(rec->inverse, rec->in, rec->out);
c@290 239 } else {
c@290 240 kiss_fft(rec->forward, rec->in, rec->out);
c@290 241 }
c@290 242 for (int i = 0; i < m_n; ++i) {
c@290 243 rout[i] = rec->out[i].r;
c@290 244 iout[i] = rec->out[i].i;
c@290 245 }
c@290 246 }
c@290 247
c@290 248 struct KissFFTRealRec {
c@290 249 kiss_fftr_cfg forward;
c@290 250 kiss_fftr_cfg inverse;
c@290 251 kiss_fft_cpx *out;
c@290 252 };
c@290 253
c@290 254 FFTReal::FFTReal(unsigned int n) :
c@290 255 m_n(n),
c@290 256 m_private(0)
c@290 257 {
c@290 258 KissFFTRealRec *rec = new KissFFTRealRec;
c@290 259 rec->forward = kiss_fftr_alloc(m_n, 0, 0, 0);
c@290 260 rec->inverse = kiss_fftr_alloc(m_n, 1, 0, 0);
c@290 261 rec->out = new kiss_fft_cpx[m_n];
c@290 262 m_private = rec;
c@290 263 }
c@290 264
c@290 265 FFTReal::~FFTReal()
c@290 266 {
c@290 267 KissFFTRealRec *rec = (KissFFTRealRec *)m_private;
c@290 268 kiss_fftr_free(rec->forward);
c@290 269 kiss_fftr_free(rec->inverse);
c@290 270 delete[] rec->out;
c@290 271 }
c@290 272
c@290 273 void
c@290 274 FFTReal::process(bool inverse,
c@290 275 const double *rin,
c@290 276 double *rout, double *iout)
c@290 277 {
c@290 278 KissFFTRealRec *rec = (KissFFTRealRec *)m_private;
c@290 279 if (inverse) {
c@290 280 kiss_fftr(rec->inverse, rin, rec->out);
c@298 281 for (int i = 0; i < m_n; ++i) {
c@298 282 rout[i] = rec->out[i].r;
c@298 283 iout[i] = rec->out[i].i;
c@298 284 }
c@290 285 } else {
c@290 286 kiss_fftr(rec->forward, rin, rec->out);
c@298 287 rout[0] = rec->out[0].r;
c@298 288 iout[0] = rec->out[0].i;
c@298 289 for (int i = 1; i < m_n/2; ++i) {
c@298 290 rout[m_n-i] = rout[i] = rec->out[i].r;
c@298 291 }
c@298 292 for (int i = 1; i < m_n/2; ++i) {
c@298 293 iout[i] = rec->out[i].i;
c@298 294 iout[m_n-i] = -iout[i];
c@298 295 }
c@298 296 rout[m_n/2] = rec->out[m_n/2].r;
c@298 297 iout[m_n/2] = rec->out[m_n/2].i;
c@290 298 }
c@290 299 }
c@290 300
c@289 301 #endif