Mercurial > hg > drum-timing-analyser
diff DrumTimingLoader_OF/chromagramm/ChordDetect.cpp @ 0:82352cfc0b23
Added files from ISMIR groove drum timing work
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Mon, 01 Oct 2012 22:24:32 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/chromagramm/ChordDetect.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,476 @@ +/* + * ChordDetect.cpp + * ChordDetect + * + * Created by Adam Stark on 28/04/2008. + * Copyright 2008 __MyCompanyName__. All rights reserved. + * + */ + +#include "ChordDetect.h" +#include <iostream> +#include <math.h> +using namespace std; + +ChordDetect :: ChordDetect() +{ + + bias = 1.06; + + makeprofiles(); + +} + +//-------------------------------------------------------------------------------------- +// destructor +ChordDetect :: ~ChordDetect() +{ + +} + + +//-------------------------------------------------------------------------------------- +// main function to be called with 8192 sample frame at 11025 Hz +void ChordDetect :: C_Detect(float c[],float c_low[]) +{ + for (int i = 0;i < 12;i++) + { + chroma[i] = c[i]; + chroma_low[i] = c_low[i]; + } + + calculateweightings(); + + classifychromagram(); + + //cout << root << " " << quality << " " << intervals << endl; +} + +//-------------------------------------------------------------------------------------- +// analyse the chromagram and assign it a root note, chord type and any features +void ChordDetect :: classifychromagram() +{ + int i; + int j; + int fifth; + int chordindex; + + // remove some of the 5th note energy from chromagram + for (i = 0;i < 12;i++) + { + fifth = (i+7) % 12; + chroma[fifth] = chroma[fifth] - (0.1*chroma[i]); + + if (chroma[fifth] < 0) + { + chroma[fifth] = 0; + } + + } + + + // major chords + for (j=0;j < 12;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // minor chords + for (j=12;j < 24;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // diminished 5th chords + for (j=24;j < 36;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // augmented 5th chords + for (j=36;j < 48;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + + chord[j] = chord[j] / weight_aug[j-36]; + } + + // sus2 chords + for (j=48;j < 60;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,3); + + chord[j] = chord[j] / weight_sus[j-48]; + } + + // sus4 chords + for (j=60;j < 72;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,3); + + chord[j] = chord[j] / weight_sus[j-60]; + } + + // major 7th chords + for (j=72;j < 84;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,4); + } + + // minor 7th chords + for (j=84;j < 96;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,4); + } + + // dominant 7th chords + for (j=96;j < 108;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,4); + } + + chordindex = minindex(chord,108); + + // major + if (chordindex < 12) + { + root = chordindex; + quality = 1; + intervals = 0; + } + + // minor + if ((chordindex >= 12) && (chordindex < 24)) + { + root = chordindex-12; + quality = 0; + intervals = 0; + } + + // diminished 5th + if ((chordindex >= 24) && (chordindex < 36)) + { + root = chordindex-24; + quality = 4; + intervals = 0; + } + + // augmented 5th + if ((chordindex >= 36) && (chordindex < 48)) + { + root = chordindex-36; + quality = 6; + intervals = 0; + } + + // sus2 + if ((chordindex >= 48) && (chordindex < 60)) + { + root = chordindex-48; + quality = 2; + intervals = 2; + } + + // sus4 + if ((chordindex >= 60) && (chordindex < 72)) + { + root = chordindex-60; + quality = 2; + intervals = 4; + } + + // major 7th + if ((chordindex >= 72) && (chordindex < 84)) + { + root = chordindex-72; + quality = 1; + intervals = 7; + } + + // minor 7th + if ((chordindex >= 84) && (chordindex < 96)) + { + root = chordindex-84; + quality = 0; + intervals = 7; + } + + // dominant 7th + if ((chordindex >= 96) && (chordindex < 108)) + { + root = chordindex-96; + quality = 2; + intervals = 7; + } +} + +//-------------------------------------------------------------------------------------- +// calculate weightings to help distinguish between sus2/sus4 and aug chords +void ChordDetect :: calculateweightings() +{ + int i; + float maxval = 0; + int fifth; + int augfifth; + + maxval = max(chroma_low,12); + + // normalise chroma low + for (i = 0;i < 12;i++) + { + chroma_low[i] = chroma_low[i] / maxval; + } + + // make weight for sus chords + for (i = 0;i < 12;i++) + { + fifth = i+7; + augfifth = i+8; + + if (fifth >= 12) + { + fifth = fifth-12; + } + + if (augfifth >= 12) + { + augfifth = augfifth-12; + } + + weight_sus[i] = chroma_low[i] + (chroma_low[fifth]/2); + weight_aug[i] = chroma_low[i] + (chroma_low[augfifth]/2); + } + + maxval = max(weight_sus,12); + // normalise weight_sus + for (i = 0;i < 12;i++) + { + weight_sus[i] = weight_sus[i] / maxval; + } + + maxval = max(weight_aug,12); + // normalise weight_aug + for (i = 0;i < 12;i++) + { + weight_aug[i] = weight_aug[i] / maxval; + } + + +} + + +//-------------------------------------------------------------------------------------- +// return delta value indicating how similar the chroma is to the chord template - lower value = more similar +float ChordDetect :: calcchordvalue(float c[],float T[],float biasval, float N) +{ + float sum = 0; + float delta; + + for (int i=0;i < 12;i++) + { + sum = sum + ((1-T[i])*(pow(c[i],2))); + } + + delta = sqrt(sum) / ((12 - N)*biasval); + + return delta; +} + + +//-------------------------------------------------------------------------------------- +// returns max value of an array +float ChordDetect :: max(float array[],int length) +{ + float max = 0; + + for (int i=0;i < length;i++) + { + if (array[i] > max) + { + max = array[i]; + } + } + + return max; +} + +//-------------------------------------------------------------------------------------- +// returns index of minimum value of array +int ChordDetect :: minindex(float array[],int length) +{ + float min = 10000; + int minindex = 0; + int i; + + for (i = 0;i < length;i++) + { + if (array[i] < min) + { + min = array[i]; + minindex = i; + } + } + + return minindex; +} + +//-------------------------------------------------------------------------------------- +// calculates bit mask chord profiles +void ChordDetect :: makeprofiles() +{ + int i; + int t; + int j = 0; + int root; + int third; + int fifth; + int seventh; + + float v1 = 1; + float v2 = 1; + float v3 = 1; + + // set profiles matrix to all zeros + for (j = 0;j < 108;j++) + { + for (t = 0;t < 12;t++) + { + profiles[j][t] = 0; + } + } + + // reset j to zero to begin creating profiles + j = 0; + + // major chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // minor chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // diminished chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+6) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // augmented chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+8) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // sus2 chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+2) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // sus4 chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+5) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // major 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + seventh = (i+11) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } + + // minor 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+7) % 12; + seventh = (i+10) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } + + // dominant 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + seventh = (i+10) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } +} \ No newline at end of file