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@309
|
7 This file 2005-2006 Christian Landone.
|
c@309
|
8
|
c@309
|
9 This program is free software; you can redistribute it and/or
|
c@309
|
10 modify it under the terms of the GNU General Public License as
|
c@309
|
11 published by the Free Software Foundation; either version 2 of the
|
c@309
|
12 License, or (at your option) any later version. See the file
|
c@309
|
13 COPYING included with this distribution for more information.
|
c@225
|
14 */
|
c@225
|
15
|
c@225
|
16 #include <iostream>
|
c@225
|
17 #include <cmath>
|
c@241
|
18 #include "maths/MathUtilities.h"
|
c@225
|
19 #include "Chromagram.h"
|
c@225
|
20
|
c@225
|
21 //----------------------------------------------------------------------------
|
c@225
|
22
|
c@276
|
23 Chromagram::Chromagram( ChromaConfig Config ) :
|
c@276
|
24 m_skGenerated(false)
|
c@225
|
25 {
|
c@225
|
26 initialise( Config );
|
c@225
|
27 }
|
c@225
|
28
|
c@225
|
29 int Chromagram::initialise( ChromaConfig Config )
|
c@225
|
30 {
|
c@225
|
31 m_FMin = Config.min; // min freq
|
c@225
|
32 m_FMax = Config.max; // max freq
|
c@225
|
33 m_BPO = Config.BPO; // bins per octave
|
c@259
|
34 m_normalise = Config.normalise; // if frame normalisation is required
|
c@225
|
35
|
cannam@468
|
36 // Extend range to a full octave
|
cannam@468
|
37 double octaves = log(m_FMax / m_FMin) / log(2.0);
|
cannam@468
|
38 m_FMax = m_FMin * pow(2.0, ceil(octaves));
|
c@225
|
39
|
c@225
|
40 // Create array for chroma result
|
c@225
|
41 m_chromadata = new double[ m_BPO ];
|
c@225
|
42
|
c@225
|
43 // Create Config Structure for ConstantQ operator
|
c@225
|
44 CQConfig ConstantQConfig;
|
c@225
|
45
|
c@225
|
46 // Populate CQ config structure with parameters
|
c@225
|
47 // inherited from the Chroma config
|
cannam@465
|
48 ConstantQConfig.FS = Config.FS;
|
c@225
|
49 ConstantQConfig.min = m_FMin;
|
c@225
|
50 ConstantQConfig.max = m_FMax;
|
c@225
|
51 ConstantQConfig.BPO = m_BPO;
|
c@225
|
52 ConstantQConfig.CQThresh = Config.CQThresh;
|
c@225
|
53
|
c@225
|
54 // Initialise ConstantQ operator
|
c@225
|
55 m_ConstantQ = new ConstantQ( ConstantQConfig );
|
c@225
|
56
|
cannam@468
|
57 // No. of constant Q bins
|
cannam@468
|
58 m_uK = m_ConstantQ->getK();
|
cannam@468
|
59
|
c@225
|
60 // Initialise working arrays
|
c@225
|
61 m_frameSize = m_ConstantQ->getfftlength();
|
c@225
|
62 m_hopSize = m_ConstantQ->gethop();
|
c@225
|
63
|
c@289
|
64 // Initialise FFT object
|
c@289
|
65 m_FFT = new FFTReal(m_frameSize);
|
c@289
|
66
|
c@225
|
67 m_FFTRe = new double[ m_frameSize ];
|
c@225
|
68 m_FFTIm = new double[ m_frameSize ];
|
c@225
|
69 m_CQRe = new double[ m_uK ];
|
c@225
|
70 m_CQIm = new double[ m_uK ];
|
c@225
|
71
|
c@257
|
72 m_window = 0;
|
c@257
|
73 m_windowbuf = 0;
|
c@257
|
74
|
c@225
|
75 return 1;
|
c@225
|
76 }
|
c@225
|
77
|
c@225
|
78 Chromagram::~Chromagram()
|
c@225
|
79 {
|
c@225
|
80 deInitialise();
|
c@225
|
81 }
|
c@225
|
82
|
c@225
|
83 int Chromagram::deInitialise()
|
c@225
|
84 {
|
c@257
|
85 delete[] m_windowbuf;
|
c@257
|
86 delete m_window;
|
c@257
|
87
|
c@225
|
88 delete [] m_chromadata;
|
c@225
|
89
|
c@225
|
90 delete m_FFT;
|
c@225
|
91
|
c@225
|
92 delete m_ConstantQ;
|
c@225
|
93
|
c@225
|
94 delete [] m_FFTRe;
|
c@225
|
95 delete [] m_FFTIm;
|
c@225
|
96 delete [] m_CQRe;
|
c@225
|
97 delete [] m_CQIm;
|
c@225
|
98 return 1;
|
c@225
|
99 }
|
c@225
|
100
|
c@225
|
101 //----------------------------------------------------------------------------------
|
c@225
|
102 // returns the absolute value of complex number xx + i*yy
|
c@225
|
103 double Chromagram::kabs(double xx, double yy)
|
c@225
|
104 {
|
c@225
|
105 double ab = sqrt(xx*xx + yy*yy);
|
c@225
|
106 return(ab);
|
c@225
|
107 }
|
c@225
|
108 //-----------------------------------------------------------------------------------
|
c@225
|
109
|
c@225
|
110
|
c@225
|
111 void Chromagram::unityNormalise(double *src)
|
c@225
|
112 {
|
c@225
|
113 double min, max;
|
c@225
|
114
|
c@225
|
115 double val = 0;
|
c@225
|
116
|
c@225
|
117 MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
|
c@225
|
118
|
c@414
|
119 for (int i = 0; i < m_BPO; i++)
|
c@225
|
120 {
|
c@225
|
121 val = src[ i ] / max;
|
c@225
|
122
|
c@225
|
123 src[ i ] = val;
|
c@225
|
124 }
|
c@225
|
125 }
|
c@225
|
126
|
c@225
|
127
|
cannam@467
|
128 double *Chromagram::process(const double *data)
|
c@225
|
129 {
|
c@276
|
130 if (!m_skGenerated) {
|
c@276
|
131 // Generate CQ Kernel
|
c@276
|
132 m_ConstantQ->sparsekernel();
|
c@276
|
133 m_skGenerated = true;
|
c@276
|
134 }
|
c@276
|
135
|
c@257
|
136 if (!m_window) {
|
c@257
|
137 m_window = new Window<double>(HammingWindow, m_frameSize);
|
c@257
|
138 m_windowbuf = new double[m_frameSize];
|
c@257
|
139 }
|
c@257
|
140
|
c@257
|
141 for (int i = 0; i < m_frameSize; ++i) {
|
c@257
|
142 m_windowbuf[i] = data[i];
|
c@257
|
143 }
|
c@257
|
144 m_window->cut(m_windowbuf);
|
c@257
|
145
|
cannam@467
|
146 // The frequency-domain version expects pre-fftshifted input - so
|
cannam@467
|
147 // we must do the same here
|
cannam@467
|
148 for (int i = 0; i < m_frameSize/2; ++i) {
|
cannam@467
|
149 double tmp = m_windowbuf[i];
|
cannam@467
|
150 m_windowbuf[i] = m_windowbuf[i + m_frameSize/2];
|
cannam@467
|
151 m_windowbuf[i + m_frameSize/2] = tmp;
|
cannam@467
|
152 }
|
cannam@467
|
153
|
c@339
|
154 m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm);
|
c@228
|
155
|
c@228
|
156 return process(m_FFTRe, m_FFTIm);
|
c@228
|
157 }
|
c@228
|
158
|
cannam@467
|
159 double *Chromagram::process(const double *real, const double *imag)
|
c@228
|
160 {
|
c@276
|
161 if (!m_skGenerated) {
|
c@276
|
162 // Generate CQ Kernel
|
c@276
|
163 m_ConstantQ->sparsekernel();
|
c@276
|
164 m_skGenerated = true;
|
c@276
|
165 }
|
c@276
|
166
|
c@228
|
167 // initialise chromadata to 0
|
c@414
|
168 for (int i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
|
c@225
|
169
|
c@225
|
170 // Calculate ConstantQ frame
|
c@228
|
171 m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
|
c@225
|
172
|
c@225
|
173 // add each octave of cq data into Chromagram
|
cannam@466
|
174 const int octaves = m_uK / m_BPO;
|
cannam@466
|
175 for (int octave = 0; octave < octaves; octave++)
|
c@225
|
176 {
|
c@414
|
177 int firstBin = octave*m_BPO;
|
c@414
|
178 for (int i = 0; i < m_BPO; i++)
|
c@225
|
179 {
|
c@225
|
180 m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
|
c@225
|
181 }
|
c@225
|
182 }
|
c@225
|
183
|
c@259
|
184 MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
|
c@225
|
185
|
c@225
|
186 return m_chromadata;
|
c@225
|
187 }
|
c@225
|
188
|
c@225
|
189
|