qm-dsp  1.8
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  Copyright (c) 2005 Centre for Digital Music ( C4DM )
4  Queen Mary Univesrity of London
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of the
9  License, or (at your option) any later version. See the file
10  COPYING included with this distribution for more information.
11 */
12 // GetKeyMode.cpp: implementation of the CGetKeyMode class.
13 //
15 
16 #include "GetKeyMode.h"
17 #include "maths/MathUtilities.h"
18 #include "base/Pitch.h"
19 
20 #include <iostream>
21 
22 #include <cstring>
23 #include <cstdlib>
24 
25 // Chords profile
26 static double MajProfile[36] =
27 { 0.0384, 0.0629, 0.0258, 0.0121, 0.0146, 0.0106, 0.0364, 0.0610, 0.0267,
28  0.0126, 0.0121, 0.0086, 0.0364, 0.0623, 0.0279, 0.0275, 0.0414, 0.0186,
29  0.0173, 0.0248, 0.0145, 0.0364, 0.0631, 0.0262, 0.0129, 0.0150, 0.0098,
30  0.0312, 0.0521, 0.0235, 0.0129, 0.0142, 0.0095, 0.0289, 0.0478, 0.0239};
31 
32 static double MinProfile[36] =
33 { 0.0375, 0.0682, 0.0299, 0.0119, 0.0138, 0.0093, 0.0296, 0.0543, 0.0257,
34  0.0292, 0.0519, 0.0246, 0.0159, 0.0234, 0.0135, 0.0291, 0.0544, 0.0248,
35  0.0137, 0.0176, 0.0104, 0.0352, 0.0670, 0.0302, 0.0222, 0.0349, 0.0164,
36  0.0174, 0.0297, 0.0166, 0.0222, 0.0401, 0.0202, 0.0175, 0.0270, 0.0146};
37 //
38 
39 
41 // Construction/Destruction
43 
44 GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
45  double hpcpAverage, double medianAverage ) :
46  m_hpcpAverage( hpcpAverage ),
47  m_medianAverage( medianAverage ),
48  m_ChrPointer(0),
49  m_DecimatedBuffer(0),
50  m_ChromaBuffer(0),
51  m_MeanHPCP(0),
52  m_MajCorr(0),
53  m_MinCorr(0),
54  m_Keys(0),
55  m_MedianFilterBuffer(0),
56  m_SortedBuffer(0),
57  m_keyStrengths(0)
58 {
60 
61  // Chromagram configuration parameters
63  m_ChromaConfig.FS = lrint(sampleRate/(double)m_DecimationFactor);
64  if (m_ChromaConfig.FS < 1) m_ChromaConfig.FS = 1;
65 
66  // Set C (= MIDI #12) as our base :
67  // This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc.
69  (48, 0, tuningFrequency);
71  (96, 0, tuningFrequency);
72 
73  m_ChromaConfig.BPO = 36;
74  m_ChromaConfig.CQThresh = 0.0054;
75 
76  // Chromagram inst.
78 
79  // Get calculated parameters from chroma object
81  // override hopsize for this application
84 
85 // std::cerr << "chroma frame size = " << m_ChromaFrameSize << ", decimation factor = " << m_DecimationFactor << " therefore block size = " << getBlockSize() << std::endl;
86 
87  // Chromagram average and estimated key median filter lengths
90 
91  // Reset counters
92  m_bufferindex = 0;
95 
96  // Spawn objectc/arrays
98 
99  m_ChromaBuffer = new double[m_BPO * m_ChromaBuffersize];
100  memset( m_ChromaBuffer, 0, sizeof(double) * m_BPO * m_ChromaBuffersize);
101 
102  m_MeanHPCP = new double[m_BPO];
103 
104  m_MajCorr = new double[m_BPO];
105  m_MinCorr = new double[m_BPO];
106  m_Keys = new double[2*m_BPO];
107 
109  memset( m_MedianFilterBuffer, 0, sizeof(int)*m_MedianWinsize);
110 
111  m_SortedBuffer = new int[ m_MedianWinsize ];
112  memset( m_SortedBuffer, 0, sizeof(int)*m_MedianWinsize);
113 
114  m_Decimator = new Decimator
115  ( m_ChromaFrameSize*m_DecimationFactor, m_DecimationFactor );
116 
117  m_keyStrengths = new double[24];
118 }
119 
121 {
122 
123  delete m_Chroma;
124  delete m_Decimator;
125 
126  delete [] m_DecimatedBuffer;
127  delete [] m_ChromaBuffer;
128  delete [] m_MeanHPCP;
129  delete [] m_MajCorr;
130  delete [] m_MinCorr;
131  delete [] m_Keys;
132  delete [] m_MedianFilterBuffer;
133  delete [] m_SortedBuffer;
134 
135  delete[] m_keyStrengths;
136 }
137 
138 double GetKeyMode::krumCorr(double *pData1, double *pData2, unsigned int length)
139 {
140  double retVal= 0.0;
141 
142  double num = 0;
143  double den = 0;
144  double mX = MathUtilities::mean( pData1, length );
145  double mY = MathUtilities::mean( pData2, length );
146 
147  double sum1 = 0;
148  double sum2 = 0;
149 
150  for( unsigned int i = 0; i <length; i++ )
151  {
152  num += ( pData1[i] - mX ) * ( pData2[i] - mY );
153 
154  sum1 += ( (pData1[i]-mX) * (pData1[i]-mX) );
155  sum2 += ( (pData2[i]-mY) * (pData2[i]-mY) );
156  }
157 
158  den = sqrt(sum1 * sum2);
159 
160  if( den>0 )
161  retVal = num/den;
162  else
163  retVal = 0;
164 
165 
166  return retVal;
167 }
168 
169 int GetKeyMode::process(double *PCMData)
170 {
171  int key;
172 
173  unsigned int j,k;
174 
177 
179 
180 
181  // Move bins such that the centre of the base note is in the
182  // middle of its three bins :
183  // Added 21.11.07 by Chris Sutton based on debugging with Katy
184  // Noland + comparison with Matlab equivalent.
186 /*
187  std::cout << "raw chroma: ";
188  for (int ii = 0; ii < m_BPO; ++ii) {
189  if (ii % (m_BPO/12) == 0) std::cout << "\n";
190  std::cout << m_ChrPointer[ii] << " ";
191  }
192  std::cout << std::endl;
193 */
194  // populate hpcp values;
195  int cbidx;
196  for( j = 0; j < m_BPO; j++ )
197  {
198  cbidx = (m_bufferindex * m_BPO) + j;
199  m_ChromaBuffer[ cbidx ] = m_ChrPointer[j];
200  }
201 
202  //keep track of input buffers;
203  if( m_bufferindex++ >= m_ChromaBuffersize - 1)
204  m_bufferindex = 0;
205 
206  // track filling of chroma matrix
209 
210  //calculate mean
211  for( k = 0; k < m_BPO; k++ )
212  {
213  double mnVal = 0.0;
214  for( j = 0; j < m_ChromaBufferFilling; j++ )
215  {
216  mnVal += m_ChromaBuffer[ k + (j*m_BPO) ];
217  }
218 
219  m_MeanHPCP[k] = mnVal/(double)m_ChromaBufferFilling;
220  }
221 
222 
223  for( k = 0; k < m_BPO; k++ )
224  {
225  m_MajCorr[k] = krumCorr( m_MeanHPCP, MajProfile, m_BPO );
226  m_MinCorr[k] = krumCorr( m_MeanHPCP, MinProfile, m_BPO );
227 
230  }
231 
232  for( k = 0; k < m_BPO; k++ )
233  {
234  m_Keys[k] = m_MajCorr[k];
235  m_Keys[k+m_BPO] = m_MinCorr[k];
236  }
237 
238  for (k = 0; k < 24; ++k) {
239  m_keyStrengths[k] = 0;
240  }
241 
242  for( k = 0; k < m_BPO*2; k++ )
243  {
244  int idx = k / (m_BPO/12);
245  int rem = k % (m_BPO/12);
246  if (rem == 0 || m_Keys[k] > m_keyStrengths[idx]) {
247  m_keyStrengths[idx] = m_Keys[k];
248  }
249 
250 // m_keyStrengths[k/(m_BPO/12)] += m_Keys[k];
251  }
252 
253 /*
254  std::cout << "raw keys: ";
255  for (int ii = 0; ii < 2*m_BPO; ++ii) {
256  if (ii % (m_BPO/12) == 0) std::cout << "\n";
257  std::cout << m_Keys[ii] << " ";
258  }
259  std::cout << std::endl;
260 
261  std::cout << "key strengths: ";
262  for (int ii = 0; ii < 24; ++ii) {
263  if (ii % 6 == 0) std::cout << "\n";
264  std::cout << m_keyStrengths[ii] << " ";
265  }
266  std::cout << std::endl;
267 */
268  double dummy;
269  // '1 +' because we number keys 1-24, not 0-23.
270  key = 1 + (int)ceil( (double)MathUtilities::getMax( m_Keys, 2* m_BPO, &dummy )/3 );
271 
272 // std::cout << "key pre-sorting: " << key << std::endl;
273 
274 
275  //Median filtering
276 
277  // track Median buffer initial filling
280 
281  //shift median buffer
282  for( k = 1; k < m_MedianWinsize; k++ )
283  {
285  }
286 
287  //write new key value into median buffer
288  m_MedianFilterBuffer[ m_MedianWinsize - 1 ] = key;
289 
290 
291  //Copy median into sorting buffer, reversed
292  unsigned int ijx = 0;
293  for( k = 0; k < m_MedianWinsize; k++ )
294  {
295  m_SortedBuffer[k] = m_MedianFilterBuffer[m_MedianWinsize-1-ijx];
296  ijx++;
297  }
298 
299  qsort(m_SortedBuffer, m_MedianBufferFilling, sizeof(unsigned int),
301 /*
302  std::cout << "sorted: ";
303  for (int ii = 0; ii < m_MedianBufferFilling; ++ii) {
304  std::cout << m_SortedBuffer[ii] << " ";
305  }
306  std::cout << std::endl;
307 */
308  int sortlength = m_MedianBufferFilling;
309  int midpoint = (int)ceil((double)sortlength/2);
310 
311 // std::cout << "midpoint = " << midpoint << endl;
312 
313  if( midpoint <= 0 )
314  midpoint = 1;
315 
316  key = m_SortedBuffer[midpoint-1];
317 
318 // std::cout << "returning key = " << key << endl;
319 
320  return key;
321 }
322 
323 
324 bool GetKeyMode::isModeMinor( int key )
325 {
326  return (key > 12);
327 }
void process(const double *src, double *dst)
Process inLength samples (as supplied to constructor) from src and write inLength / decFactor samples...
Definition: Decimator.cpp:200
double CQThresh
Definition: Chromagram.h:28
int process(double *PCMData)
Definition: GetKeyMode.cpp:169
double min
Definition: Chromagram.h:25
unsigned int m_ChromaHopSize
Definition: GetKeyMode.h:65
unsigned int BPO
Definition: Chromagram.h:27
double * m_MajCorr
Definition: GetKeyMode.h:82
double * m_keyStrengths
Definition: GetKeyMode.h:88
double * m_ChromaBuffer
Definition: GetKeyMode.h:79
static double MajProfile[36]
Definition: GetKeyMode.cpp:26
unsigned int FS
Definition: Chromagram.h:24
double * process(const double *data)
Definition: Chromagram.cpp:124
unsigned int m_MedianWinsize
Definition: GetKeyMode.h:71
double max
Definition: Chromagram.h:26
static void circShift(double *data, int length, int shift)
int * m_SortedBuffer
Definition: GetKeyMode.h:86
unsigned int getFrameSize()
Definition: Chromagram.h:48
double * m_ChrPointer
Definition: GetKeyMode.h:60
MathUtilities::NormaliseType normalise
Definition: Chromagram.h:29
ChromaConfig m_ChromaConfig
Definition: GetKeyMode.h:54
Decimator * m_Decimator
Definition: GetKeyMode.h:51
virtual ~GetKeyMode()
Definition: GetKeyMode.cpp:120
double m_hpcpAverage
Definition: GetKeyMode.h:46
unsigned int m_ChromaBufferFilling
Definition: GetKeyMode.h:74
unsigned int m_ChromaBuffersize
Definition: GetKeyMode.h:70
double * m_MinCorr
Definition: GetKeyMode.h:83
bool isModeMinor(int key)
Definition: GetKeyMode.cpp:324
static double mean(const double *src, unsigned int len)
Return the mean of the given array of the given length.
double * m_DecimatedBuffer
Definition: GetKeyMode.h:78
static float getFrequencyForPitch(int midiPitch, float centsOffset=0, float concertA=440.0)
Definition: Pitch.cpp:20
unsigned int m_MedianBufferFilling
Definition: GetKeyMode.h:75
Chromagram * m_Chroma
Definition: GetKeyMode.h:57
int * m_MedianFilterBuffer
Definition: GetKeyMode.h:85
GetKeyMode(int sampleRate, float tuningFrequency, double hpcpAverage, double medianAverage)
Definition: GetKeyMode.cpp:44
unsigned int m_ChromaFrameSize
Definition: GetKeyMode.h:63
static int compareInt(const void *a, const void *b)
unsigned int m_BPO
Definition: GetKeyMode.h:67
double m_medianAverage
Definition: GetKeyMode.h:47
unsigned int m_DecimationFactor
Definition: GetKeyMode.h:48
Decimator carries out a fast downsample by a power-of-two factor.
Definition: Decimator.h:24
double * m_Keys
Definition: GetKeyMode.h:84
static double MinProfile[36]
Definition: GetKeyMode.cpp:32
unsigned int m_bufferindex
Definition: GetKeyMode.h:73
double krumCorr(double *pData1, double *pData2, unsigned int length)
Definition: GetKeyMode.cpp:138
static int getMax(double *data, unsigned int length, double *max=0)
double * m_MeanHPCP
Definition: GetKeyMode.h:80