GetKeyMode.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3  QM DSP Library
4 
5  Centre for Digital Music, Queen Mary, University of London.
6  This file 2005-2006 Christian Landone and Katy Noland.
7 
8  Fixes to correct chroma offsets and for thread safety contributed
9  by Daniel Schürmann.
10 
11  This program is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 2 of the
14  License, or (at your option) any later version. See the file
15  COPYING included with this distribution for more information.
16 */
17 
18 #include "GetKeyMode.h"
19 
22 
23 #include "maths/MathUtilities.h"
24 #include "base/Pitch.h"
25 
26 #include <iostream>
27 
28 #include <cstring>
29 #include <cstdlib>
30 
31 static const int kBinsPerOctave = 36;
32 
33 // Chords profile
34 static double MajProfile[kBinsPerOctave] = {
35  0.0384, 0.0629, 0.0258, 0.0121, 0.0146, 0.0106, 0.0364, 0.0610, 0.0267,
36  0.0126, 0.0121, 0.0086, 0.0364, 0.0623, 0.0279, 0.0275, 0.0414, 0.0186,
37  0.0173, 0.0248, 0.0145, 0.0364, 0.0631, 0.0262, 0.0129, 0.0150, 0.0098,
38  0.0312, 0.0521, 0.0235, 0.0129, 0.0142, 0.0095, 0.0289, 0.0478, 0.0239
39 };
40 
41 static double MinProfile[kBinsPerOctave] = {
42  0.0375, 0.0682, 0.0299, 0.0119, 0.0138, 0.0093, 0.0296, 0.0543, 0.0257,
43  0.0292, 0.0519, 0.0246, 0.0159, 0.0234, 0.0135, 0.0291, 0.0544, 0.0248,
44  0.0137, 0.0176, 0.0104, 0.0352, 0.0670, 0.0302, 0.0222, 0.0349, 0.0164,
45  0.0174, 0.0297, 0.0166, 0.0222, 0.0401, 0.0202, 0.0175, 0.0270, 0.0146
46 };
47 //
48 
49 
51 // Construction/Destruction
53 
55  m_hpcpAverage(config.hpcpAverage),
56  m_medianAverage(config.medianAverage),
57  m_decimationFactor(config.decimationFactor),
58  m_chrPointer(0),
59  m_decimatedBuffer(0),
60  m_chromaBuffer(0),
61  m_meanHPCP(0),
62  m_majCorr(0),
63  m_minCorr(0),
64  m_medianFilterBuffer(0),
65  m_sortedBuffer(0),
66  m_keyStrengths(0)
67 {
68  ChromaConfig chromaConfig;
69 
70  // Chromagram configuration parameters
72  chromaConfig.FS = config.sampleRate / (double)m_decimationFactor;
73  if (chromaConfig.FS < 1) {
74  chromaConfig.FS = 1;
75  }
76 
77  // Set C3 (= MIDI #48) as our base:
78  // This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc.
79  chromaConfig.min =
81  chromaConfig.max =
83 
84  chromaConfig.BPO = kBinsPerOctave;
85  chromaConfig.CQThresh = 0.0054;
86 
87  // Chromagram inst.
88  m_chroma = new Chromagram(chromaConfig);
89 
90  // Get calculated parameters from chroma object
92 
93  // override hopsize for this application
95 
96 // std::cerr << "chroma frame size = " << m_ChromaFrameSize << ", decimation factor = " << m_DecimationFactor << " therefore block size = " << getBlockSize() << std::endl;
97 
98  // Chromagram average and estimated key median filter lengths
99  m_chromaBufferSize = (int)ceil
100  (m_hpcpAverage * chromaConfig.FS / m_chromaFrameSize);
101  m_medianWinSize = (int)ceil
102  (m_medianAverage * chromaConfig.FS / m_chromaFrameSize);
103 
104  // Reset counters
105  m_bufferIndex = 0;
108 
109  // Spawn objectc/arrays
110  m_decimatedBuffer = new double[m_chromaFrameSize];
112 
113  memset(m_chromaBuffer, 0,
114  sizeof(double) * kBinsPerOctave * m_chromaBufferSize);
115 
116  m_meanHPCP = new double[kBinsPerOctave];
117 
118  m_majCorr = new double[kBinsPerOctave];
119  m_minCorr = new double[kBinsPerOctave];
120 
121  m_majProfileNorm = new double[kBinsPerOctave];
122  m_minProfileNorm = new double[kBinsPerOctave];
123 
126 
127  for (int i = 0; i < kBinsPerOctave; i++) {
128  m_majProfileNorm[i] = MajProfile[i] - mMaj;
129  m_minProfileNorm[i] = MinProfile[i] - mMin;
130  }
131 
133  memset( m_medianFilterBuffer, 0, sizeof(int)*m_medianWinSize);
134 
135  m_sortedBuffer = new int[ m_medianWinSize ];
136  memset( m_sortedBuffer, 0, sizeof(int)*m_medianWinSize);
137 
139  m_decimationFactor );
140 
141  m_keyStrengths = new double[24];
142 }
143 
145 {
146  delete m_chroma;
147  delete m_decimator;
148 
149  delete [] m_decimatedBuffer;
150  delete [] m_chromaBuffer;
151  delete [] m_meanHPCP;
152  delete [] m_majCorr;
153  delete [] m_minCorr;
154  delete [] m_majProfileNorm;
155  delete [] m_minProfileNorm;
156  delete [] m_medianFilterBuffer;
157  delete [] m_sortedBuffer;
158  delete [] m_keyStrengths;
159 }
160 
161 double GetKeyMode::krumCorr( const double *pDataNorm, const double *pProfileNorm,
162  int shiftProfile, int length)
163 {
164  double retVal= 0.0;
165 
166  double num = 0;
167  double den = 0;
168  double sum1 = 0;
169  double sum2 = 0;
170 
171  for (int i = 0; i < length; i++) {
172 
173  int k = (i - shiftProfile + length) % length;
174 
175  num += pDataNorm[i] * pProfileNorm[k];
176 
177  sum1 += (pDataNorm[i] * pDataNorm[i]);
178  sum2 += (pProfileNorm[k] * pProfileNorm[k]);
179  }
180 
181  den = sqrt(sum1 * sum2);
182 
183  if (den > 0) {
184  retVal = num/den;
185  } else {
186  retVal = 0;
187  }
188 
189  return retVal;
190 }
191 
192 int GetKeyMode::process(double *pcmData)
193 {
194  int key;
195  int j, k;
196 
198 
200 
201  // populate hpcp values
202  int cbidx;
203  for (j = 0;j < kBinsPerOctave;j++ ) {
204  cbidx = (m_bufferIndex * kBinsPerOctave) + j;
205  m_chromaBuffer[ cbidx ] = m_chrPointer[j];
206  }
207 
208  // keep track of input buffers
209  if (m_bufferIndex++ >= m_chromaBufferSize - 1) {
210  m_bufferIndex = 0;
211  }
212 
213  // track filling of chroma matrix
216  }
217 
218  // calculate mean
219  for (k = 0; k < kBinsPerOctave; k++) {
220  double mnVal = 0.0;
221  for (j = 0; j < m_chromaBufferFilling; j++) {
222  mnVal += m_chromaBuffer[ k + (j * kBinsPerOctave) ];
223  }
224 
225  m_meanHPCP[k] = mnVal / (double)m_chromaBufferFilling;
226  }
227 
228  // Normalize for zero average
229  double mHPCP = MathUtilities::mean(m_meanHPCP, kBinsPerOctave);
230  for (k = 0; k < kBinsPerOctave; k++) {
231  m_meanHPCP[k] -= mHPCP;
232  }
233 
234  for (k = 0; k < kBinsPerOctave; k++) {
235  // The Chromagram has the center of C at bin 0, while the major
236  // and minor profiles have the center of C at 1. We want to have
237  // the correlation for C result also at 1.
238  // To achieve this we have to shift two times:
239  m_majCorr[k] = krumCorr
240  (m_meanHPCP, m_majProfileNorm, k - 2, kBinsPerOctave);
241  m_minCorr[k] = krumCorr
242  (m_meanHPCP, m_minProfileNorm, k - 2, kBinsPerOctave);
243  }
244 
245  // m_MajCorr[1] is C center 1 / 3 + 1 = 1
246  // m_MajCorr[4] is D center 4 / 3 + 1 = 2
247  // '+ 1' because we number keys 1-24, not 0-23.
248  double maxMaj;
249  int maxMajBin = MathUtilities::getMax(m_majCorr, kBinsPerOctave, &maxMaj);
250  double maxMin;
251  int maxMinBin = MathUtilities::getMax(m_minCorr, kBinsPerOctave, &maxMin);
252  int maxBin = (maxMaj > maxMin) ? maxMajBin : (maxMinBin + kBinsPerOctave);
253  key = maxBin / 3 + 1;
254 
255  // Median filtering
256 
257  // track Median buffer initial filling
260  }
261 
262  // shift median buffer
263  for (k = 1; k < m_medianWinSize; k++ ) {
265  }
266 
267  // write new key value into median buffer
268  m_medianFilterBuffer[ m_medianWinSize - 1 ] = key;
269 
270  // copy median into sorting buffer, reversed
271  int ijx = 0;
272  for (k = 0; k < m_medianWinSize; k++) {
273  m_sortedBuffer[k] = m_medianFilterBuffer[m_medianWinSize - 1 - ijx];
274  ijx++;
275  }
276 
277  qsort(m_sortedBuffer, m_medianBufferFilling, sizeof(int),
279 
280  int sortlength = m_medianBufferFilling;
281  int midpoint = (int)ceil((double)sortlength / 2);
282 
283  if (midpoint <= 0) {
284  midpoint = 1;
285  }
286 
287  key = m_sortedBuffer[midpoint-1];
288 
289  return key;
290 }
291 
293  int k;
294 
295  for (k = 0; k < 24; ++k) {
296  m_keyStrengths[k] = 0;
297  }
298 
299  for (k = 0; k < kBinsPerOctave; k++) {
300  int idx = k / (kBinsPerOctave/12);
301  int rem = k % (kBinsPerOctave/12);
302  if (rem == 0 || m_majCorr[k] > m_keyStrengths[idx]) {
303  m_keyStrengths[idx] = m_majCorr[k];
304  }
305  }
306 
307  for (k = 0; k < kBinsPerOctave; k++) {
308  int idx = (k + kBinsPerOctave) / (kBinsPerOctave/12);
309  int rem = k % (kBinsPerOctave/12);
310  if (rem == 0 || m_minCorr[k] > m_keyStrengths[idx]) {
311  m_keyStrengths[idx] = m_minCorr[k];
312  }
313  }
314 
315  return m_keyStrengths;
316 }
double * m_meanHPCP
Definition: GetKeyMode.h:103
void process(const double *src, double *dst)
Process inLength samples (as supplied to constructor) from src and write inLength / decFactor samples...
Definition: Decimator.cpp:195
double * m_majCorr
Definition: GetKeyMode.h:107
double CQThresh
Definition: Chromagram.h:27
double min
Definition: Chromagram.h:24
int * m_medianFilterBuffer
Definition: GetKeyMode.h:109
double * m_majProfileNorm
Definition: GetKeyMode.h:105
double * m_keyStrengths
Definition: GetKeyMode.h:112
Chromagram * m_chroma
Definition: GetKeyMode.h:83
double * process(const double *data)
Process a time-domain input signal of length equal to getFrameSize().
Definition: Chromagram.cpp:124
double max
Definition: Chromagram.h:25
int m_decimationFactor
Definition: GetKeyMode.h:77
int m_medianWinSize
Definition: GetKeyMode.h:95
double * m_decimatedBuffer
Definition: GetKeyMode.h:101
MathUtilities::NormaliseType normalise
Definition: Chromagram.h:28
double * m_chromaBuffer
Definition: GetKeyMode.h:102
int m_chromaHopSize
Definition: GetKeyMode.h:92
int process(double *pcmData)
Process a single time-domain input sample frame of length getBlockSize().
Definition: GetKeyMode.cpp:192
virtual ~GetKeyMode()
Definition: GetKeyMode.cpp:144
double m_hpcpAverage
Definition: GetKeyMode.h:75
GetKeyMode(Config config)
Definition: GetKeyMode.cpp:54
double krumCorr(const double *pDataNorm, const double *pProfileNorm, int shiftProfile, int length)
Definition: GetKeyMode.cpp:161
static double MinProfile[kBinsPerOctave]
Definition: GetKeyMode.cpp:41
int * m_sortedBuffer
Definition: GetKeyMode.h:110
double FS
Definition: Chromagram.h:23
int m_bufferIndex
Definition: GetKeyMode.h:97
static int getMax(double *data, int length, double *max=0)
double * getKeyStrengths()
Return a pointer to an internal 24-element array containing the correlation of the chroma vector gene...
Definition: GetKeyMode.cpp:292
double * m_chrPointer
Definition: GetKeyMode.h:86
static float getFrequencyForPitch(int midiPitch, float centsOffset=0, float concertA=440.0)
Definition: Pitch.cpp:20
static double MajProfile[kBinsPerOctave]
Definition: GetKeyMode.cpp:34
int m_chromaBufferFilling
Definition: GetKeyMode.h:98
int getFrameSize()
Definition: Chromagram.h:71
double * m_minCorr
Definition: GetKeyMode.h:108
Decimator * m_decimator
Definition: GetKeyMode.h:80
static int compareInt(const void *a, const void *b)
static const int kBinsPerOctave
Definition: GetKeyMode.cpp:31
double m_medianAverage
Definition: GetKeyMode.h:76
Decimator carries out a fast downsample by a power-of-two factor.
Definition: Decimator.h:24
double * m_minProfileNorm
Definition: GetKeyMode.h:106
int m_medianBufferFilling
Definition: GetKeyMode.h:99
int m_chromaFrameSize
Definition: GetKeyMode.h:89
int m_chromaBufferSize
Definition: GetKeyMode.h:94
static double mean(const double *src, int len)
Return the mean of the given array of the given length.