annotate dsp/transforms/FFT.cpp @ 96:88f3cfcff55f

A threshold (delta) is added in the peak picking parameters structure (PPickParams). It is used as an offset when computing the smoothed detection function. A constructor for the structure PPickParams is also added to set the parameters to 0 when a structure instance is created. Hence programmes using the peak picking parameter structure and which do not set the delta parameter (e.g. QM Vamp note onset detector) won't be affected by the modifications. Functions modified: - dsp/onsets/PeakPicking.cpp - dsp/onsets/PeakPicking.h - dsp/signalconditioning/DFProcess.cpp - dsp/signalconditioning/DFProcess.h
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Mon, 20 Jun 2011 19:01:48 +0100
parents e5907ae6de17
children f6ccde089491
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 /*
cannam@0 4 QM DSP Library
cannam@0 5
cannam@0 6 Centre for Digital Music, Queen Mary, University of London.
cannam@0 7 This file is based on Don Cross's public domain FFT implementation.
cannam@0 8 */
cannam@0 9
cannam@0 10 #include "FFT.h"
cannam@55 11
cannam@55 12 #include "maths/MathUtilities.h"
cannam@55 13
cannam@0 14 #include <cmath>
cannam@0 15
cannam@55 16 #include <iostream>
cannam@55 17
cannam@64 18 FFT::FFT(unsigned int n) :
cannam@64 19 m_n(n),
cannam@64 20 m_private(0)
cannam@0 21 {
cannam@64 22 if( !MathUtilities::isPowerOfTwo(m_n) )
cannam@64 23 {
cannam@64 24 std::cerr << "ERROR: FFT: Non-power-of-two FFT size "
cannam@64 25 << m_n << " not supported in this implementation"
cannam@64 26 << std::endl;
cannam@64 27 return;
cannam@64 28 }
cannam@0 29 }
cannam@0 30
cannam@0 31 FFT::~FFT()
cannam@0 32 {
cannam@0 33
cannam@0 34 }
cannam@0 35
cannam@64 36 FFTReal::FFTReal(unsigned int n) :
cannam@64 37 m_n(n),
cannam@64 38 m_private(0)
cannam@0 39 {
cannam@64 40 m_private = new FFT(m_n);
cannam@64 41 }
cannam@0 42
cannam@64 43 FFTReal::~FFTReal()
cannam@64 44 {
cannam@64 45 delete (FFT *)m_private;
cannam@64 46 }
cannam@64 47
cannam@64 48 void
cannam@64 49 FFTReal::process(bool inverse,
cannam@64 50 const double *realIn,
cannam@64 51 double *realOut, double *imagOut)
cannam@64 52 {
cannam@64 53 ((FFT *)m_private)->process(inverse, realIn, 0, realOut, imagOut);
cannam@64 54 }
cannam@64 55
cannam@64 56 static unsigned int numberOfBitsNeeded(unsigned int p_nSamples)
cannam@64 57 {
cannam@64 58 int i;
cannam@64 59
cannam@64 60 if( p_nSamples < 2 )
cannam@64 61 {
cannam@64 62 return 0;
cannam@64 63 }
cannam@64 64
cannam@64 65 for ( i=0; ; i++ )
cannam@64 66 {
cannam@64 67 if( p_nSamples & (1 << i) ) return i;
cannam@64 68 }
cannam@64 69 }
cannam@64 70
cannam@64 71 static unsigned int reverseBits(unsigned int p_nIndex, unsigned int p_nBits)
cannam@64 72 {
cannam@64 73 unsigned int i, rev;
cannam@64 74
cannam@64 75 for(i=rev=0; i < p_nBits; i++)
cannam@64 76 {
cannam@64 77 rev = (rev << 1) | (p_nIndex & 1);
cannam@64 78 p_nIndex >>= 1;
cannam@64 79 }
cannam@64 80
cannam@64 81 return rev;
cannam@64 82 }
cannam@64 83
cannam@64 84 void
cannam@64 85 FFT::process(bool p_bInverseTransform,
cannam@64 86 const double *p_lpRealIn, const double *p_lpImagIn,
cannam@64 87 double *p_lpRealOut, double *p_lpImagOut)
cannam@64 88 {
cannam@66 89 if (!p_lpRealIn || !p_lpRealOut || !p_lpImagOut) return;
cannam@66 90
cannam@66 91 // std::cerr << "FFT::process(" << m_n << "," << p_bInverseTransform << ")" << std::endl;
cannam@0 92
cannam@0 93 unsigned int NumBits;
cannam@0 94 unsigned int i, j, k, n;
cannam@0 95 unsigned int BlockSize, BlockEnd;
cannam@0 96
cannam@0 97 double angle_numerator = 2.0 * M_PI;
cannam@0 98 double tr, ti;
cannam@0 99
cannam@64 100 if( !MathUtilities::isPowerOfTwo(m_n) )
cannam@0 101 {
cannam@55 102 std::cerr << "ERROR: FFT::process: Non-power-of-two FFT size "
cannam@64 103 << m_n << " not supported in this implementation"
cannam@55 104 << std::endl;
cannam@0 105 return;
cannam@0 106 }
cannam@0 107
cannam@0 108 if( p_bInverseTransform ) angle_numerator = -angle_numerator;
cannam@0 109
cannam@64 110 NumBits = numberOfBitsNeeded ( m_n );
cannam@0 111
cannam@0 112
cannam@64 113 for( i=0; i < m_n; i++ )
cannam@0 114 {
cannam@0 115 j = reverseBits ( i, NumBits );
cannam@0 116 p_lpRealOut[j] = p_lpRealIn[i];
cannam@0 117 p_lpImagOut[j] = (p_lpImagIn == 0) ? 0.0 : p_lpImagIn[i];
cannam@0 118 }
cannam@0 119
cannam@0 120
cannam@0 121 BlockEnd = 1;
cannam@64 122 for( BlockSize = 2; BlockSize <= m_n; BlockSize <<= 1 )
cannam@0 123 {
cannam@0 124 double delta_angle = angle_numerator / (double)BlockSize;
cannam@0 125 double sm2 = -sin ( -2 * delta_angle );
cannam@0 126 double sm1 = -sin ( -delta_angle );
cannam@0 127 double cm2 = cos ( -2 * delta_angle );
cannam@0 128 double cm1 = cos ( -delta_angle );
cannam@0 129 double w = 2 * cm1;
cannam@0 130 double ar[3], ai[3];
cannam@0 131
cannam@64 132 for( i=0; i < m_n; i += BlockSize )
cannam@0 133 {
cannam@0 134
cannam@0 135 ar[2] = cm2;
cannam@0 136 ar[1] = cm1;
cannam@0 137
cannam@0 138 ai[2] = sm2;
cannam@0 139 ai[1] = sm1;
cannam@0 140
cannam@0 141 for ( j=i, n=0; n < BlockEnd; j++, n++ )
cannam@0 142 {
cannam@0 143
cannam@0 144 ar[0] = w*ar[1] - ar[2];
cannam@0 145 ar[2] = ar[1];
cannam@0 146 ar[1] = ar[0];
cannam@0 147
cannam@0 148 ai[0] = w*ai[1] - ai[2];
cannam@0 149 ai[2] = ai[1];
cannam@0 150 ai[1] = ai[0];
cannam@0 151
cannam@0 152 k = j + BlockEnd;
cannam@0 153 tr = ar[0]*p_lpRealOut[k] - ai[0]*p_lpImagOut[k];
cannam@0 154 ti = ar[0]*p_lpImagOut[k] + ai[0]*p_lpRealOut[k];
cannam@0 155
cannam@0 156 p_lpRealOut[k] = p_lpRealOut[j] - tr;
cannam@0 157 p_lpImagOut[k] = p_lpImagOut[j] - ti;
cannam@0 158
cannam@0 159 p_lpRealOut[j] += tr;
cannam@0 160 p_lpImagOut[j] += ti;
cannam@0 161
cannam@0 162 }
cannam@0 163 }
cannam@0 164
cannam@0 165 BlockEnd = BlockSize;
cannam@0 166
cannam@0 167 }
cannam@0 168
cannam@0 169
cannam@0 170 if( p_bInverseTransform )
cannam@0 171 {
cannam@64 172 double denom = (double)m_n;
cannam@0 173
cannam@64 174 for ( i=0; i < m_n; i++ )
cannam@0 175 {
cannam@0 176 p_lpRealOut[i] /= denom;
cannam@0 177 p_lpImagOut[i] /= denom;
cannam@0 178 }
cannam@0 179 }
cannam@0 180 }
cannam@0 181