comparison dsp/keydetection/GetKeyMode.cpp @ 462:bfd7d7633e1d

Merge branch 'keydetection_rounding' into chroma-key-tuning-review
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 28 May 2019 13:45:08 +0100
parents 9414df58fd0e
children 0076c66d2932
comparison
equal deleted inserted replaced
455:38932adb6c02 462:bfd7d7633e1d
20 #include <iostream> 20 #include <iostream>
21 21
22 #include <cstring> 22 #include <cstring>
23 #include <cstdlib> 23 #include <cstdlib>
24 24
25 static const int kBinsPerOctave = 36;
26
25 // Chords profile 27 // Chords profile
26 static double MajProfile[36] = 28 static double MajProfile[kBinsPerOctave] = {
27 { 0.0384, 0.0629, 0.0258, 0.0121, 0.0146, 0.0106, 0.0364, 0.0610, 0.0267, 29 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, 30 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, 31 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}; 32 0.0312, 0.0521, 0.0235, 0.0129, 0.0142, 0.0095, 0.0289, 0.0478, 0.0239};
31 33
32 static double MinProfile[36] = 34 static double MinProfile[kBinsPerOctave] = {
33 { 0.0375, 0.0682, 0.0299, 0.0119, 0.0138, 0.0093, 0.0296, 0.0543, 0.0257, 35 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, 36 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, 37 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}; 38 0.0174, 0.0297, 0.0166, 0.0222, 0.0401, 0.0202, 0.0175, 0.0270, 0.0146};
37 // 39 //
38 40
39 41
40 ////////////////////////////////////////////////////////////////////// 42 //////////////////////////////////////////////////////////////////////
41 // Construction/Destruction 43 // Construction/Destruction
42 ////////////////////////////////////////////////////////////////////// 44 //////////////////////////////////////////////////////////////////////
43 45
44 GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency, 46 GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
45 double hpcpAverage, double medianAverage ) : 47 double hpcpAverage, double medianAverage ) :
46 m_hpcpAverage( hpcpAverage ), 48 m_hpcpAverage( hpcpAverage ),
47 m_medianAverage( medianAverage ), 49 m_medianAverage( medianAverage ),
48 m_ChrPointer(0), 50 m_ChrPointer(0),
49 m_DecimatedBuffer(0), 51 m_DecimatedBuffer(0),
50 m_ChromaBuffer(0), 52 m_ChromaBuffer(0),
51 m_MeanHPCP(0), 53 m_MeanHPCP(0),
52 m_MajCorr(0), 54 m_MajCorr(0),
53 m_MinCorr(0), 55 m_MinCorr(0),
54 m_Keys(0),
55 m_MedianFilterBuffer(0), 56 m_MedianFilterBuffer(0),
56 m_SortedBuffer(0), 57 m_SortedBuffer(0),
57 m_keyStrengths(0) 58 m_keyStrengths(0)
58 { 59 {
59 m_DecimationFactor = 8; 60 m_DecimationFactor = 8;
60 61
61 // Chromagram configuration parameters 62 // Chromagram configuration parameters
62 m_ChromaConfig.normalise = MathUtilities::NormaliseUnitMax; 63 m_ChromaConfig.normalise = MathUtilities::NormaliseUnitMax;
63 m_ChromaConfig.FS = lrint(sampleRate/(double)m_DecimationFactor); 64 m_ChromaConfig.FS = sampleRate/(double)m_DecimationFactor;
64 if (m_ChromaConfig.FS < 1) m_ChromaConfig.FS = 1; 65 if (m_ChromaConfig.FS < 1) {
65 66 m_ChromaConfig.FS = 1;
66 // Set C (= MIDI #12) as our base : 67 }
68
69 // Set C3 (= MIDI #48) as our base:
67 // This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc. 70 // This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc.
68 m_ChromaConfig.min = Pitch::getFrequencyForPitch 71 m_ChromaConfig.min = Pitch::getFrequencyForPitch( 48, 0, tuningFrequency );
69 (48, 0, tuningFrequency); 72 m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, 0, tuningFrequency );
70 m_ChromaConfig.max = Pitch::getFrequencyForPitch 73
71 (96, 0, tuningFrequency); 74 m_ChromaConfig.BPO = kBinsPerOctave;
72
73 m_ChromaConfig.BPO = 36;
74 m_ChromaConfig.CQThresh = 0.0054; 75 m_ChromaConfig.CQThresh = 0.0054;
75 76
76 // Chromagram inst. 77 // Chromagram inst.
77 m_Chroma = new Chromagram( m_ChromaConfig ); 78 m_Chroma = new Chromagram( m_ChromaConfig );
78 79
79 // Get calculated parameters from chroma object 80 // Get calculated parameters from chroma object
80 m_ChromaFrameSize = m_Chroma->getFrameSize(); 81 m_ChromaFrameSize = m_Chroma->getFrameSize();
81 // override hopsize for this application 82 // override hopsize for this application
82 m_ChromaHopSize = m_ChromaFrameSize; 83 m_ChromaHopSize = m_ChromaFrameSize;
83 m_BPO = m_ChromaConfig.BPO;
84 84
85 // std::cerr << "chroma frame size = " << m_ChromaFrameSize << ", decimation factor = " << m_DecimationFactor << " therefore block size = " << getBlockSize() << std::endl; 85 // std::cerr << "chroma frame size = " << m_ChromaFrameSize << ", decimation factor = " << m_DecimationFactor << " therefore block size = " << getBlockSize() << std::endl;
86 86
87 // Chromagram average and estimated key median filter lengths 87 // Chromagram average and estimated key median filter lengths
88 m_ChromaBuffersize = (int)ceil( m_hpcpAverage * m_ChromaConfig.FS/m_ChromaFrameSize ); 88 m_ChromaBuffersize = (int)ceil( m_hpcpAverage * m_ChromaConfig.FS/m_ChromaFrameSize );
94 m_MedianBufferFilling = 0; 94 m_MedianBufferFilling = 0;
95 95
96 // Spawn objectc/arrays 96 // Spawn objectc/arrays
97 m_DecimatedBuffer = new double[m_ChromaFrameSize]; 97 m_DecimatedBuffer = new double[m_ChromaFrameSize];
98 98
99 m_ChromaBuffer = new double[m_BPO * m_ChromaBuffersize]; 99 m_ChromaBuffer = new double[kBinsPerOctave * m_ChromaBuffersize];
100 memset( m_ChromaBuffer, 0, sizeof(double) * m_BPO * m_ChromaBuffersize); 100 memset( m_ChromaBuffer, 0, sizeof(double) * kBinsPerOctave * m_ChromaBuffersize);
101 101
102 m_MeanHPCP = new double[m_BPO]; 102 m_MeanHPCP = new double[kBinsPerOctave];
103 103
104 m_MajCorr = new double[m_BPO]; 104 m_MajCorr = new double[kBinsPerOctave];
105 m_MinCorr = new double[m_BPO]; 105 m_MinCorr = new double[kBinsPerOctave];
106 m_Keys = new double[2*m_BPO]; 106
107 107 m_MajProfileNorm = new double[kBinsPerOctave];
108 m_MinProfileNorm = new double[kBinsPerOctave];
109
110 double mMaj = MathUtilities::mean( MajProfile, kBinsPerOctave );
111 double mMin = MathUtilities::mean( MinProfile, kBinsPerOctave );
112
113 for( unsigned int i = 0; i < kBinsPerOctave; i++ ) {
114 m_MajProfileNorm[i] = MajProfile[i] - mMaj;
115 m_MinProfileNorm[i] = MinProfile[i] - mMin;
116 }
117
108 m_MedianFilterBuffer = new int[ m_MedianWinsize ]; 118 m_MedianFilterBuffer = new int[ m_MedianWinsize ];
109 memset( m_MedianFilterBuffer, 0, sizeof(int)*m_MedianWinsize); 119 memset( m_MedianFilterBuffer, 0, sizeof(int)*m_MedianWinsize);
110 120
111 m_SortedBuffer = new int[ m_MedianWinsize ]; 121 m_SortedBuffer = new int[ m_MedianWinsize ];
112 memset( m_SortedBuffer, 0, sizeof(int)*m_MedianWinsize); 122 memset( m_SortedBuffer, 0, sizeof(int)*m_MedianWinsize);
113 123
114 m_Decimator = new Decimator 124 m_Decimator = new Decimator( m_ChromaFrameSize*m_DecimationFactor, m_DecimationFactor );
115 ( m_ChromaFrameSize*m_DecimationFactor, m_DecimationFactor );
116 125
117 m_keyStrengths = new double[24]; 126 m_keyStrengths = new double[24];
118 } 127 }
119 128
120 GetKeyMode::~GetKeyMode() 129 GetKeyMode::~GetKeyMode()
121 { 130 {
122
123 delete m_Chroma; 131 delete m_Chroma;
124 delete m_Decimator; 132 delete m_Decimator;
125 133
126 delete [] m_DecimatedBuffer; 134 delete [] m_DecimatedBuffer;
127 delete [] m_ChromaBuffer; 135 delete [] m_ChromaBuffer;
128 delete [] m_MeanHPCP; 136 delete [] m_MeanHPCP;
129 delete [] m_MajCorr; 137 delete [] m_MajCorr;
130 delete [] m_MinCorr; 138 delete [] m_MinCorr;
131 delete [] m_Keys; 139 delete [] m_MajProfileNorm;
140 delete [] m_MinProfileNorm;
132 delete [] m_MedianFilterBuffer; 141 delete [] m_MedianFilterBuffer;
133 delete [] m_SortedBuffer; 142 delete [] m_SortedBuffer;
134 143 delete [] m_keyStrengths;
135 delete[] m_keyStrengths; 144 }
136 } 145
137 146 double GetKeyMode::krumCorr( const double *pDataNorm, const double *pProfileNorm,
138 double GetKeyMode::krumCorr(double *pData1, double *pData2, unsigned int length) 147 int shiftProfile, unsigned int length)
139 { 148 {
140 double retVal= 0.0; 149 double retVal= 0.0;
141 150
142 double num = 0; 151 double num = 0;
143 double den = 0; 152 double den = 0;
144 double mX = MathUtilities::mean( pData1, length );
145 double mY = MathUtilities::mean( pData2, length );
146
147 double sum1 = 0; 153 double sum1 = 0;
148 double sum2 = 0; 154 double sum2 = 0;
149 155
150 for( unsigned int i = 0; i <length; i++ ) 156 for( unsigned int i = 0; i <length; i++ )
151 { 157 {
152 num += ( pData1[i] - mX ) * ( pData2[i] - mY ); 158 int k = (i - shiftProfile + length) % length;
153 159
154 sum1 += ( (pData1[i]-mX) * (pData1[i]-mX) ); 160 num += pDataNorm[i] * pProfileNorm[k];
155 sum2 += ( (pData2[i]-mY) * (pData2[i]-mY) ); 161
162 sum1 += ( pDataNorm[i] * pDataNorm[i] );
163 sum2 += ( pProfileNorm[k] * pProfileNorm[k] );
156 } 164 }
157 165
158 den = sqrt(sum1 * sum2); 166 den = sqrt(sum1 * sum2);
159 167
160 if( den>0 ) 168 if( den>0 ) {
161 retVal = num/den; 169 retVal = num/den;
162 else 170 } else {
163 retVal = 0; 171 retVal = 0;
164 172 }
165 173
166 return retVal; 174 return retVal;
167 } 175 }
168 176
169 int GetKeyMode::process(double *PCMData) 177 int GetKeyMode::process(double *PCMData)
170 { 178 {
171 int key; 179 int key;
172
173 unsigned int j,k; 180 unsigned int j,k;
174 181
175 ////////////////////////////////////////////// 182 //////////////////////////////////////////////
176 m_Decimator->process( PCMData, m_DecimatedBuffer); 183 m_Decimator->process( PCMData, m_DecimatedBuffer);
177 184
178 m_ChrPointer = m_Chroma->process( m_DecimatedBuffer ); 185 m_ChrPointer = m_Chroma->process( m_DecimatedBuffer );
179 186
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.
185 MathUtilities::circShift( m_ChrPointer, m_BPO, 1);
186 /* 187 /*
187 std::cout << "raw chroma: "; 188 std::cout << "raw chroma: ";
188 for (int ii = 0; ii < m_BPO; ++ii) { 189 for (int ii = 0; ii < kBinsPerOctave; ++ii) {
189 if (ii % (m_BPO/12) == 0) std::cout << "\n"; 190 if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
190 std::cout << m_ChrPointer[ii] << " "; 191 std::cout << m_ChrPointer[ii] << " ";
191 } 192 }
192 std::cout << std::endl; 193 std::cout << std::endl;
193 */ 194 */
194 // populate hpcp values; 195 // populate hpcp values;
195 int cbidx; 196 int cbidx;
196 for( j = 0; j < m_BPO; j++ ) 197 for( j = 0; j < kBinsPerOctave; j++ ) {
197 { 198 cbidx = (m_bufferindex * kBinsPerOctave) + j;
198 cbidx = (m_bufferindex * m_BPO) + j;
199 m_ChromaBuffer[ cbidx ] = m_ChrPointer[j]; 199 m_ChromaBuffer[ cbidx ] = m_ChrPointer[j];
200 } 200 }
201 201
202 //keep track of input buffers; 202 //keep track of input buffers;
203 if( m_bufferindex++ >= m_ChromaBuffersize - 1) 203 if( m_bufferindex++ >= m_ChromaBuffersize - 1) {
204 m_bufferindex = 0; 204 m_bufferindex = 0;
205 }
205 206
206 // track filling of chroma matrix 207 // track filling of chroma matrix
207 if( m_ChromaBufferFilling++ >= m_ChromaBuffersize) 208 if( m_ChromaBufferFilling++ >= m_ChromaBuffersize) {
208 m_ChromaBufferFilling = m_ChromaBuffersize; 209 m_ChromaBufferFilling = m_ChromaBuffersize;
209 210 }
210 //calculate mean 211
211 for( k = 0; k < m_BPO; k++ ) 212 //calculate mean
212 { 213 for( k = 0; k < kBinsPerOctave; k++ ) {
213 double mnVal = 0.0; 214 double mnVal = 0.0;
214 for( j = 0; j < m_ChromaBufferFilling; j++ ) 215 for( j = 0; j < m_ChromaBufferFilling; j++ ) {
215 { 216 mnVal += m_ChromaBuffer[ k + (j*kBinsPerOctave) ];
216 mnVal += m_ChromaBuffer[ k + (j*m_BPO) ];
217 } 217 }
218 218
219 m_MeanHPCP[k] = mnVal/(double)m_ChromaBufferFilling; 219 m_MeanHPCP[k] = mnVal/(double)m_ChromaBufferFilling;
220 } 220 }
221 221
222 222 // Normalize for zero average
223 for( k = 0; k < m_BPO; k++ ) 223 double mHPCP = MathUtilities::mean( m_MeanHPCP, kBinsPerOctave );
224 { 224 for( k = 0; k < kBinsPerOctave; k++ )
225 m_MajCorr[k] = krumCorr( m_MeanHPCP, MajProfile, m_BPO ); 225 {
226 m_MinCorr[k] = krumCorr( m_MeanHPCP, MinProfile, m_BPO ); 226 m_MeanHPCP[k] -= mHPCP;
227 227 }
228 MathUtilities::circShift( MajProfile, m_BPO, 1 ); 228
229 MathUtilities::circShift( MinProfile, m_BPO, 1 ); 229
230 } 230 for( k = 0; k < kBinsPerOctave; k++ )
231 231 {
232 for( k = 0; k < m_BPO; k++ ) 232 // The Cromagram has the center of C at bin 0, while the major
233 { 233 // and minor profiles have the center of C at 1. We want to have
234 m_Keys[k] = m_MajCorr[k]; 234 // the correlation for C result also at 1.
235 m_Keys[k+m_BPO] = m_MinCorr[k]; 235 // To achieve this we have to shift two times:
236 } 236 m_MajCorr[k] = krumCorr( m_MeanHPCP, m_MajProfileNorm, (int)k - 2, kBinsPerOctave );
237 237 m_MinCorr[k] = krumCorr( m_MeanHPCP, m_MinProfileNorm, (int)k - 2, kBinsPerOctave );
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 } 238 }
252 239
253 /* 240 /*
254 std::cout << "raw keys: "; 241 std::cout << "raw keys: ";
255 for (int ii = 0; ii < 2*m_BPO; ++ii) { 242 for (int ii = 0; ii < kBinsPerOctave; ++ii) {
256 if (ii % (m_BPO/12) == 0) std::cout << "\n"; 243 if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
257 std::cout << m_Keys[ii] << " "; 244 std::cout << m_MajCorr[ii] << " ";
245 }
246 for (int ii = 0; ii < kBinsPerOctave; ++ii) {
247 if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
248 std::cout << m_MinCorr[ii] << " ";
258 } 249 }
259 std::cout << std::endl; 250 std::cout << std::endl;
260 251 */
261 std::cout << "key strengths: "; 252
262 for (int ii = 0; ii < 24; ++ii) { 253 // m_MajCorr[1] is C center 1 / 3 + 1 = 1
263 if (ii % 6 == 0) std::cout << "\n"; 254 // m_MajCorr[4] is D center 4 / 3 + 1 = 2
264 std::cout << m_keyStrengths[ii] << " "; 255 // '+ 1' because we number keys 1-24, not 0-23.
265 } 256 double maxMaj;
266 std::cout << std::endl; 257 int maxMajBin = MathUtilities::getMax( m_MajCorr, kBinsPerOctave, &maxMaj );
267 */ 258 double maxMin;
268 double dummy; 259 int maxMinBin = MathUtilities::getMax( m_MinCorr, kBinsPerOctave, &maxMin );
269 // '1 +' because we number keys 1-24, not 0-23. 260 int maxBin = (maxMaj > maxMin) ? maxMajBin : (maxMinBin + kBinsPerOctave);
270 key = 1 + (int)ceil( (double)MathUtilities::getMax( m_Keys, 2* m_BPO, &dummy )/3 ); 261 key = maxBin / 3 + 1;
271 262
263 // std::cout << "fractional key pre-sorting: " << (maxBin + 2) / 3.0 << std::endl;
272 // std::cout << "key pre-sorting: " << key << std::endl; 264 // std::cout << "key pre-sorting: " << key << std::endl;
273 265
274 266
275 //Median filtering 267 //Median filtering
276 268
277 // track Median buffer initial filling 269 // track Median buffer initial filling
278 if( m_MedianBufferFilling++ >= m_MedianWinsize) 270 if( m_MedianBufferFilling++ >= m_MedianWinsize) {
279 m_MedianBufferFilling = m_MedianWinsize; 271 m_MedianBufferFilling = m_MedianWinsize;
280 272 }
273
281 //shift median buffer 274 //shift median buffer
282 for( k = 1; k < m_MedianWinsize; k++ ) 275 for( k = 1; k < m_MedianWinsize; k++ ) {
283 {
284 m_MedianFilterBuffer[ k - 1 ] = m_MedianFilterBuffer[ k ]; 276 m_MedianFilterBuffer[ k - 1 ] = m_MedianFilterBuffer[ k ];
285 } 277 }
286 278
287 //write new key value into median buffer 279 //write new key value into median buffer
288 m_MedianFilterBuffer[ m_MedianWinsize - 1 ] = key; 280 m_MedianFilterBuffer[ m_MedianWinsize - 1 ] = key;
289 281
290 282
291 //Copy median into sorting buffer, reversed 283 //Copy median into sorting buffer, reversed
292 unsigned int ijx = 0; 284 unsigned int ijx = 0;
293 for( k = 0; k < m_MedianWinsize; k++ ) 285 for( k = 0; k < m_MedianWinsize; k++ ) {
294 {
295 m_SortedBuffer[k] = m_MedianFilterBuffer[m_MedianWinsize-1-ijx]; 286 m_SortedBuffer[k] = m_MedianFilterBuffer[m_MedianWinsize-1-ijx];
296 ijx++; 287 ijx++;
297 } 288 }
298 289
299 qsort(m_SortedBuffer, m_MedianBufferFilling, sizeof(unsigned int), 290 qsort(m_SortedBuffer, m_MedianBufferFilling, sizeof(unsigned int),
308 int sortlength = m_MedianBufferFilling; 299 int sortlength = m_MedianBufferFilling;
309 int midpoint = (int)ceil((double)sortlength/2); 300 int midpoint = (int)ceil((double)sortlength/2);
310 301
311 // std::cout << "midpoint = " << midpoint << endl; 302 // std::cout << "midpoint = " << midpoint << endl;
312 303
313 if( midpoint <= 0 ) 304 if( midpoint <= 0 ) {
314 midpoint = 1; 305 midpoint = 1;
306 }
315 307
316 key = m_SortedBuffer[midpoint-1]; 308 key = m_SortedBuffer[midpoint-1];
317 309
318 // std::cout << "returning key = " << key << endl; 310 // std::cout << "returning key = " << key << endl;
319 311
323 315
324 bool GetKeyMode::isModeMinor( int key ) 316 bool GetKeyMode::isModeMinor( int key )
325 { 317 {
326 return (key > 12); 318 return (key > 12);
327 } 319 }
320
321 unsigned int getChromaSize()
322 {
323 return kBinsPerOctave;
324 }
325
326 double* GetKeyMode::getKeyStrengths() {
327 unsigned int k;
328
329 for (k = 0; k < 24; ++k) {
330 m_keyStrengths[k] = 0;
331 }
332
333 for( k = 0; k < kBinsPerOctave; k++ )
334 {
335 int idx = k / (kBinsPerOctave/12);
336 int rem = k % (kBinsPerOctave/12);
337 if (rem == 0 || m_MajCorr[k] > m_keyStrengths[idx]) {
338 m_keyStrengths[idx] = m_MajCorr[k];
339 }
340 }
341
342 for( k = 0; k < kBinsPerOctave; k++ )
343 {
344 int idx = (k + kBinsPerOctave) / (kBinsPerOctave/12);
345 int rem = k % (kBinsPerOctave/12);
346 if (rem == 0 || m_MinCorr[k] > m_keyStrengths[idx]) {
347 m_keyStrengths[idx] = m_MinCorr[k];
348 }
349 }
350
351 /*
352 std::cout << "key strengths: ";
353 for (int ii = 0; ii < 24; ++ii) {
354 if (ii % 6 == 0) std::cout << "\n";
355 std::cout << m_keyStrengths[ii] << " ";
356 }
357 std::cout << std::endl;
358 */
359
360 return m_keyStrengths;
361 }