andrew@0
|
1 /*
|
andrew@0
|
2 * ChordDetect.cpp
|
andrew@0
|
3 * ChordDetect
|
andrew@0
|
4 *
|
andrew@0
|
5 * Created by Adam Stark on 28/04/2008.
|
andrew@0
|
6 * Copyright 2008 __MyCompanyName__. All rights reserved.
|
andrew@0
|
7 *
|
andrew@0
|
8 */
|
andrew@0
|
9
|
andrew@0
|
10 #include "ChordDetect.h"
|
andrew@0
|
11 #include <iostream>
|
andrew@0
|
12 #include <math.h>
|
andrew@0
|
13 using namespace std;
|
andrew@0
|
14
|
andrew@0
|
15 ChordDetect :: ChordDetect()
|
andrew@0
|
16 {
|
andrew@0
|
17
|
andrew@0
|
18 bias = 1.06;
|
andrew@0
|
19
|
andrew@0
|
20 makeprofiles();
|
andrew@0
|
21
|
andrew@0
|
22 }
|
andrew@0
|
23
|
andrew@0
|
24 //--------------------------------------------------------------------------------------
|
andrew@0
|
25 // destructor
|
andrew@0
|
26 ChordDetect :: ~ChordDetect()
|
andrew@0
|
27 {
|
andrew@0
|
28
|
andrew@0
|
29 }
|
andrew@0
|
30
|
andrew@0
|
31
|
andrew@0
|
32 //--------------------------------------------------------------------------------------
|
andrew@0
|
33 // main function to be called with 8192 sample frame at 11025 Hz
|
andrew@0
|
34 void ChordDetect :: C_Detect(float c[],float c_low[])
|
andrew@0
|
35 {
|
andrew@0
|
36 for (int i = 0;i < 12;i++)
|
andrew@0
|
37 {
|
andrew@0
|
38 chroma[i] = c[i];
|
andrew@0
|
39 chroma_low[i] = c_low[i];
|
andrew@0
|
40 }
|
andrew@0
|
41
|
andrew@0
|
42 calculateweightings();
|
andrew@0
|
43
|
andrew@0
|
44 classifychromagram();
|
andrew@0
|
45
|
andrew@0
|
46 //cout << root << " " << quality << " " << intervals << endl;
|
andrew@0
|
47 }
|
andrew@0
|
48
|
andrew@0
|
49 //--------------------------------------------------------------------------------------
|
andrew@0
|
50 // analyse the chromagram and assign it a root note, chord type and any features
|
andrew@0
|
51 void ChordDetect :: classifychromagram()
|
andrew@0
|
52 {
|
andrew@0
|
53 int i;
|
andrew@0
|
54 int j;
|
andrew@0
|
55 int fifth;
|
andrew@0
|
56 int chordindex;
|
andrew@0
|
57
|
andrew@0
|
58 // remove some of the 5th note energy from chromagram
|
andrew@0
|
59 for (i = 0;i < 12;i++)
|
andrew@0
|
60 {
|
andrew@0
|
61 fifth = (i+7) % 12;
|
andrew@0
|
62 chroma[fifth] = chroma[fifth] - (0.1*chroma[i]);
|
andrew@0
|
63
|
andrew@0
|
64 if (chroma[fifth] < 0)
|
andrew@0
|
65 {
|
andrew@0
|
66 chroma[fifth] = 0;
|
andrew@0
|
67 }
|
andrew@0
|
68
|
andrew@0
|
69 }
|
andrew@0
|
70
|
andrew@0
|
71
|
andrew@0
|
72 // major chords
|
andrew@0
|
73 for (j=0;j < 12;j++)
|
andrew@0
|
74 {
|
andrew@0
|
75 chord[j] = calcchordvalue(chroma,profiles[j],bias,3);
|
andrew@0
|
76 }
|
andrew@0
|
77
|
andrew@0
|
78 // minor chords
|
andrew@0
|
79 for (j=12;j < 24;j++)
|
andrew@0
|
80 {
|
andrew@0
|
81 chord[j] = calcchordvalue(chroma,profiles[j],bias,3);
|
andrew@0
|
82 }
|
andrew@0
|
83
|
andrew@0
|
84 // diminished 5th chords
|
andrew@0
|
85 for (j=24;j < 36;j++)
|
andrew@0
|
86 {
|
andrew@0
|
87 chord[j] = calcchordvalue(chroma,profiles[j],bias,3);
|
andrew@0
|
88 }
|
andrew@0
|
89
|
andrew@0
|
90 // augmented 5th chords
|
andrew@0
|
91 for (j=36;j < 48;j++)
|
andrew@0
|
92 {
|
andrew@0
|
93 chord[j] = calcchordvalue(chroma,profiles[j],bias,3);
|
andrew@0
|
94
|
andrew@0
|
95 chord[j] = chord[j] / weight_aug[j-36];
|
andrew@0
|
96 }
|
andrew@0
|
97
|
andrew@0
|
98 // sus2 chords
|
andrew@0
|
99 for (j=48;j < 60;j++)
|
andrew@0
|
100 {
|
andrew@0
|
101 chord[j] = calcchordvalue(chroma,profiles[j],1,3);
|
andrew@0
|
102
|
andrew@0
|
103 chord[j] = chord[j] / weight_sus[j-48];
|
andrew@0
|
104 }
|
andrew@0
|
105
|
andrew@0
|
106 // sus4 chords
|
andrew@0
|
107 for (j=60;j < 72;j++)
|
andrew@0
|
108 {
|
andrew@0
|
109 chord[j] = calcchordvalue(chroma,profiles[j],1,3);
|
andrew@0
|
110
|
andrew@0
|
111 chord[j] = chord[j] / weight_sus[j-60];
|
andrew@0
|
112 }
|
andrew@0
|
113
|
andrew@0
|
114 // major 7th chords
|
andrew@0
|
115 for (j=72;j < 84;j++)
|
andrew@0
|
116 {
|
andrew@0
|
117 chord[j] = calcchordvalue(chroma,profiles[j],1,4);
|
andrew@0
|
118 }
|
andrew@0
|
119
|
andrew@0
|
120 // minor 7th chords
|
andrew@0
|
121 for (j=84;j < 96;j++)
|
andrew@0
|
122 {
|
andrew@0
|
123 chord[j] = calcchordvalue(chroma,profiles[j],bias,4);
|
andrew@0
|
124 }
|
andrew@0
|
125
|
andrew@0
|
126 // dominant 7th chords
|
andrew@0
|
127 for (j=96;j < 108;j++)
|
andrew@0
|
128 {
|
andrew@0
|
129 chord[j] = calcchordvalue(chroma,profiles[j],bias,4);
|
andrew@0
|
130 }
|
andrew@0
|
131
|
andrew@0
|
132 chordindex = minindex(chord,108);
|
andrew@0
|
133
|
andrew@0
|
134 // major
|
andrew@0
|
135 if (chordindex < 12)
|
andrew@0
|
136 {
|
andrew@0
|
137 root = chordindex;
|
andrew@0
|
138 quality = 1;
|
andrew@0
|
139 intervals = 0;
|
andrew@0
|
140 }
|
andrew@0
|
141
|
andrew@0
|
142 // minor
|
andrew@0
|
143 if ((chordindex >= 12) && (chordindex < 24))
|
andrew@0
|
144 {
|
andrew@0
|
145 root = chordindex-12;
|
andrew@0
|
146 quality = 0;
|
andrew@0
|
147 intervals = 0;
|
andrew@0
|
148 }
|
andrew@0
|
149
|
andrew@0
|
150 // diminished 5th
|
andrew@0
|
151 if ((chordindex >= 24) && (chordindex < 36))
|
andrew@0
|
152 {
|
andrew@0
|
153 root = chordindex-24;
|
andrew@0
|
154 quality = 4;
|
andrew@0
|
155 intervals = 0;
|
andrew@0
|
156 }
|
andrew@0
|
157
|
andrew@0
|
158 // augmented 5th
|
andrew@0
|
159 if ((chordindex >= 36) && (chordindex < 48))
|
andrew@0
|
160 {
|
andrew@0
|
161 root = chordindex-36;
|
andrew@0
|
162 quality = 6;
|
andrew@0
|
163 intervals = 0;
|
andrew@0
|
164 }
|
andrew@0
|
165
|
andrew@0
|
166 // sus2
|
andrew@0
|
167 if ((chordindex >= 48) && (chordindex < 60))
|
andrew@0
|
168 {
|
andrew@0
|
169 root = chordindex-48;
|
andrew@0
|
170 quality = 2;
|
andrew@0
|
171 intervals = 2;
|
andrew@0
|
172 }
|
andrew@0
|
173
|
andrew@0
|
174 // sus4
|
andrew@0
|
175 if ((chordindex >= 60) && (chordindex < 72))
|
andrew@0
|
176 {
|
andrew@0
|
177 root = chordindex-60;
|
andrew@0
|
178 quality = 2;
|
andrew@0
|
179 intervals = 4;
|
andrew@0
|
180 }
|
andrew@0
|
181
|
andrew@0
|
182 // major 7th
|
andrew@0
|
183 if ((chordindex >= 72) && (chordindex < 84))
|
andrew@0
|
184 {
|
andrew@0
|
185 root = chordindex-72;
|
andrew@0
|
186 quality = 1;
|
andrew@0
|
187 intervals = 7;
|
andrew@0
|
188 }
|
andrew@0
|
189
|
andrew@0
|
190 // minor 7th
|
andrew@0
|
191 if ((chordindex >= 84) && (chordindex < 96))
|
andrew@0
|
192 {
|
andrew@0
|
193 root = chordindex-84;
|
andrew@0
|
194 quality = 0;
|
andrew@0
|
195 intervals = 7;
|
andrew@0
|
196 }
|
andrew@0
|
197
|
andrew@0
|
198 // dominant 7th
|
andrew@0
|
199 if ((chordindex >= 96) && (chordindex < 108))
|
andrew@0
|
200 {
|
andrew@0
|
201 root = chordindex-96;
|
andrew@0
|
202 quality = 2;
|
andrew@0
|
203 intervals = 7;
|
andrew@0
|
204 }
|
andrew@0
|
205 }
|
andrew@0
|
206
|
andrew@0
|
207 //--------------------------------------------------------------------------------------
|
andrew@0
|
208 // calculate weightings to help distinguish between sus2/sus4 and aug chords
|
andrew@0
|
209 void ChordDetect :: calculateweightings()
|
andrew@0
|
210 {
|
andrew@0
|
211 int i;
|
andrew@0
|
212 float maxval = 0;
|
andrew@0
|
213 int fifth;
|
andrew@0
|
214 int augfifth;
|
andrew@0
|
215
|
andrew@0
|
216 maxval = max(chroma_low,12);
|
andrew@0
|
217
|
andrew@0
|
218 // normalise chroma low
|
andrew@0
|
219 for (i = 0;i < 12;i++)
|
andrew@0
|
220 {
|
andrew@0
|
221 chroma_low[i] = chroma_low[i] / maxval;
|
andrew@0
|
222 }
|
andrew@0
|
223
|
andrew@0
|
224 // make weight for sus chords
|
andrew@0
|
225 for (i = 0;i < 12;i++)
|
andrew@0
|
226 {
|
andrew@0
|
227 fifth = i+7;
|
andrew@0
|
228 augfifth = i+8;
|
andrew@0
|
229
|
andrew@0
|
230 if (fifth >= 12)
|
andrew@0
|
231 {
|
andrew@0
|
232 fifth = fifth-12;
|
andrew@0
|
233 }
|
andrew@0
|
234
|
andrew@0
|
235 if (augfifth >= 12)
|
andrew@0
|
236 {
|
andrew@0
|
237 augfifth = augfifth-12;
|
andrew@0
|
238 }
|
andrew@0
|
239
|
andrew@0
|
240 weight_sus[i] = chroma_low[i] + (chroma_low[fifth]/2);
|
andrew@0
|
241 weight_aug[i] = chroma_low[i] + (chroma_low[augfifth]/2);
|
andrew@0
|
242 }
|
andrew@0
|
243
|
andrew@0
|
244 maxval = max(weight_sus,12);
|
andrew@0
|
245 // normalise weight_sus
|
andrew@0
|
246 for (i = 0;i < 12;i++)
|
andrew@0
|
247 {
|
andrew@0
|
248 weight_sus[i] = weight_sus[i] / maxval;
|
andrew@0
|
249 }
|
andrew@0
|
250
|
andrew@0
|
251 maxval = max(weight_aug,12);
|
andrew@0
|
252 // normalise weight_aug
|
andrew@0
|
253 for (i = 0;i < 12;i++)
|
andrew@0
|
254 {
|
andrew@0
|
255 weight_aug[i] = weight_aug[i] / maxval;
|
andrew@0
|
256 }
|
andrew@0
|
257
|
andrew@0
|
258
|
andrew@0
|
259 }
|
andrew@0
|
260
|
andrew@0
|
261
|
andrew@0
|
262 //--------------------------------------------------------------------------------------
|
andrew@0
|
263 // return delta value indicating how similar the chroma is to the chord template - lower value = more similar
|
andrew@0
|
264 float ChordDetect :: calcchordvalue(float c[],float T[],float biasval, float N)
|
andrew@0
|
265 {
|
andrew@0
|
266 float sum = 0;
|
andrew@0
|
267 float delta;
|
andrew@0
|
268
|
andrew@0
|
269 for (int i=0;i < 12;i++)
|
andrew@0
|
270 {
|
andrew@0
|
271 sum = sum + ((1-T[i])*(pow(c[i],2)));
|
andrew@0
|
272 }
|
andrew@0
|
273
|
andrew@0
|
274 delta = sqrt(sum) / ((12 - N)*biasval);
|
andrew@0
|
275
|
andrew@0
|
276 return delta;
|
andrew@0
|
277 }
|
andrew@0
|
278
|
andrew@0
|
279
|
andrew@0
|
280 //--------------------------------------------------------------------------------------
|
andrew@0
|
281 // returns max value of an array
|
andrew@0
|
282 float ChordDetect :: max(float array[],int length)
|
andrew@0
|
283 {
|
andrew@0
|
284 float max = 0;
|
andrew@0
|
285
|
andrew@0
|
286 for (int i=0;i < length;i++)
|
andrew@0
|
287 {
|
andrew@0
|
288 if (array[i] > max)
|
andrew@0
|
289 {
|
andrew@0
|
290 max = array[i];
|
andrew@0
|
291 }
|
andrew@0
|
292 }
|
andrew@0
|
293
|
andrew@0
|
294 return max;
|
andrew@0
|
295 }
|
andrew@0
|
296
|
andrew@0
|
297 //--------------------------------------------------------------------------------------
|
andrew@0
|
298 // returns index of minimum value of array
|
andrew@0
|
299 int ChordDetect :: minindex(float array[],int length)
|
andrew@0
|
300 {
|
andrew@0
|
301 float min = 10000;
|
andrew@0
|
302 int minindex = 0;
|
andrew@0
|
303 int i;
|
andrew@0
|
304
|
andrew@0
|
305 for (i = 0;i < length;i++)
|
andrew@0
|
306 {
|
andrew@0
|
307 if (array[i] < min)
|
andrew@0
|
308 {
|
andrew@0
|
309 min = array[i];
|
andrew@0
|
310 minindex = i;
|
andrew@0
|
311 }
|
andrew@0
|
312 }
|
andrew@0
|
313
|
andrew@0
|
314 return minindex;
|
andrew@0
|
315 }
|
andrew@0
|
316
|
andrew@0
|
317 //--------------------------------------------------------------------------------------
|
andrew@0
|
318 // calculates bit mask chord profiles
|
andrew@0
|
319 void ChordDetect :: makeprofiles()
|
andrew@0
|
320 {
|
andrew@0
|
321 int i;
|
andrew@0
|
322 int t;
|
andrew@0
|
323 int j = 0;
|
andrew@0
|
324 int root;
|
andrew@0
|
325 int third;
|
andrew@0
|
326 int fifth;
|
andrew@0
|
327 int seventh;
|
andrew@0
|
328
|
andrew@0
|
329 float v1 = 1;
|
andrew@0
|
330 float v2 = 1;
|
andrew@0
|
331 float v3 = 1;
|
andrew@0
|
332
|
andrew@0
|
333 // set profiles matrix to all zeros
|
andrew@0
|
334 for (j = 0;j < 108;j++)
|
andrew@0
|
335 {
|
andrew@0
|
336 for (t = 0;t < 12;t++)
|
andrew@0
|
337 {
|
andrew@0
|
338 profiles[j][t] = 0;
|
andrew@0
|
339 }
|
andrew@0
|
340 }
|
andrew@0
|
341
|
andrew@0
|
342 // reset j to zero to begin creating profiles
|
andrew@0
|
343 j = 0;
|
andrew@0
|
344
|
andrew@0
|
345 // major chords
|
andrew@0
|
346 for (i = 0;i < 12;i++)
|
andrew@0
|
347 {
|
andrew@0
|
348 root = i % 12;
|
andrew@0
|
349 third = (i+4) % 12;
|
andrew@0
|
350 fifth = (i+7) % 12;
|
andrew@0
|
351
|
andrew@0
|
352 profiles[j][root] = v1;
|
andrew@0
|
353 profiles[j][third] = v2;
|
andrew@0
|
354 profiles[j][fifth] = v3;
|
andrew@0
|
355
|
andrew@0
|
356 j++;
|
andrew@0
|
357 }
|
andrew@0
|
358
|
andrew@0
|
359 // minor chords
|
andrew@0
|
360 for (i = 0;i < 12;i++)
|
andrew@0
|
361 {
|
andrew@0
|
362 root = i % 12;
|
andrew@0
|
363 third = (i+3) % 12;
|
andrew@0
|
364 fifth = (i+7) % 12;
|
andrew@0
|
365
|
andrew@0
|
366 profiles[j][root] = v1;
|
andrew@0
|
367 profiles[j][third] = v2;
|
andrew@0
|
368 profiles[j][fifth] = v3;
|
andrew@0
|
369
|
andrew@0
|
370 j++;
|
andrew@0
|
371 }
|
andrew@0
|
372
|
andrew@0
|
373 // diminished chords
|
andrew@0
|
374 for (i = 0;i < 12;i++)
|
andrew@0
|
375 {
|
andrew@0
|
376 root = i % 12;
|
andrew@0
|
377 third = (i+3) % 12;
|
andrew@0
|
378 fifth = (i+6) % 12;
|
andrew@0
|
379
|
andrew@0
|
380 profiles[j][root] = v1;
|
andrew@0
|
381 profiles[j][third] = v2;
|
andrew@0
|
382 profiles[j][fifth] = v3;
|
andrew@0
|
383
|
andrew@0
|
384 j++;
|
andrew@0
|
385 }
|
andrew@0
|
386
|
andrew@0
|
387 // augmented chords
|
andrew@0
|
388 for (i = 0;i < 12;i++)
|
andrew@0
|
389 {
|
andrew@0
|
390 root = i % 12;
|
andrew@0
|
391 third = (i+4) % 12;
|
andrew@0
|
392 fifth = (i+8) % 12;
|
andrew@0
|
393
|
andrew@0
|
394 profiles[j][root] = v1;
|
andrew@0
|
395 profiles[j][third] = v2;
|
andrew@0
|
396 profiles[j][fifth] = v3;
|
andrew@0
|
397
|
andrew@0
|
398 j++;
|
andrew@0
|
399 }
|
andrew@0
|
400
|
andrew@0
|
401 // sus2 chords
|
andrew@0
|
402 for (i = 0;i < 12;i++)
|
andrew@0
|
403 {
|
andrew@0
|
404 root = i % 12;
|
andrew@0
|
405 third = (i+2) % 12;
|
andrew@0
|
406 fifth = (i+7) % 12;
|
andrew@0
|
407
|
andrew@0
|
408 profiles[j][root] = v1;
|
andrew@0
|
409 profiles[j][third] = v2;
|
andrew@0
|
410 profiles[j][fifth] = v3;
|
andrew@0
|
411
|
andrew@0
|
412 j++;
|
andrew@0
|
413 }
|
andrew@0
|
414
|
andrew@0
|
415 // sus4 chords
|
andrew@0
|
416 for (i = 0;i < 12;i++)
|
andrew@0
|
417 {
|
andrew@0
|
418 root = i % 12;
|
andrew@0
|
419 third = (i+5) % 12;
|
andrew@0
|
420 fifth = (i+7) % 12;
|
andrew@0
|
421
|
andrew@0
|
422 profiles[j][root] = v1;
|
andrew@0
|
423 profiles[j][third] = v2;
|
andrew@0
|
424 profiles[j][fifth] = v3;
|
andrew@0
|
425
|
andrew@0
|
426 j++;
|
andrew@0
|
427 }
|
andrew@0
|
428
|
andrew@0
|
429 // major 7th chords
|
andrew@0
|
430 for (i = 0;i < 12;i++)
|
andrew@0
|
431 {
|
andrew@0
|
432 root = i % 12;
|
andrew@0
|
433 third = (i+4) % 12;
|
andrew@0
|
434 fifth = (i+7) % 12;
|
andrew@0
|
435 seventh = (i+11) % 12;
|
andrew@0
|
436
|
andrew@0
|
437 profiles[j][root] = v1;
|
andrew@0
|
438 profiles[j][third] = v2;
|
andrew@0
|
439 profiles[j][fifth] = v3;
|
andrew@0
|
440 profiles[j][seventh] = v3;
|
andrew@0
|
441
|
andrew@0
|
442 j++;
|
andrew@0
|
443 }
|
andrew@0
|
444
|
andrew@0
|
445 // minor 7th chords
|
andrew@0
|
446 for (i = 0;i < 12;i++)
|
andrew@0
|
447 {
|
andrew@0
|
448 root = i % 12;
|
andrew@0
|
449 third = (i+3) % 12;
|
andrew@0
|
450 fifth = (i+7) % 12;
|
andrew@0
|
451 seventh = (i+10) % 12;
|
andrew@0
|
452
|
andrew@0
|
453 profiles[j][root] = v1;
|
andrew@0
|
454 profiles[j][third] = v2;
|
andrew@0
|
455 profiles[j][fifth] = v3;
|
andrew@0
|
456 profiles[j][seventh] = v3;
|
andrew@0
|
457
|
andrew@0
|
458 j++;
|
andrew@0
|
459 }
|
andrew@0
|
460
|
andrew@0
|
461 // dominant 7th chords
|
andrew@0
|
462 for (i = 0;i < 12;i++)
|
andrew@0
|
463 {
|
andrew@0
|
464 root = i % 12;
|
andrew@0
|
465 third = (i+4) % 12;
|
andrew@0
|
466 fifth = (i+7) % 12;
|
andrew@0
|
467 seventh = (i+10) % 12;
|
andrew@0
|
468
|
andrew@0
|
469 profiles[j][root] = v1;
|
andrew@0
|
470 profiles[j][third] = v2;
|
andrew@0
|
471 profiles[j][fifth] = v3;
|
andrew@0
|
472 profiles[j][seventh] = v3;
|
andrew@0
|
473
|
andrew@0
|
474 j++;
|
andrew@0
|
475 }
|
andrew@0
|
476 } |