Mercurial > hg > audio-time-warp
view chromagramm/ChordDetect.cpp @ 0:572c856e38ac
Starting up openFrameworks project for audio time warping. The ofxFileReader goes in addons of your OF folder, the libraries and source (chromogram, fftw and source code src+ timewarp) are probably best kept in the repository, then dragged into the project afresh. That way, as we update the repository, the code that the openFrameworks project looks for will be updated.
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Tue, 17 May 2011 08:48:58 +0100 |
parents | |
children |
line wrap: on
line source
/* * 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++; } }