## Saturday, April 16, 2011

### Decomposing a song into chords, Part 3

In the last part, we showed how to reconstruct a reasonably accurate train of notes at each time interval throughout a song, using real guitar audio input.  In this part, we reconstruct the parent chords from which the notes originate at each instant in time.  Starting where we left with the note_intervals variable, after filtering out transients and duplicates, we take the remaining notes at each time interval and attempt to place them in parent chords.

The first step is to define the allowable structures of parent chords.  This is done by setting up a matrix of interval groupings, one row for each chord.  In this part, we will limit the matrix to just the 12 chords with a major third and perfect fifth.  The resulting 12x3 chord table defines the chord structures for the 12x1 vector of notes from part 1.
`(1) notes = [27.5; ...     // A             29.13524; ... // A#             30.86771; ... // B             32.7032; ...  // C             34.64783; ... // C#             36.7081; ...  // D             38.89087; ... // D#             20.60172; ... // E             21.82676; ... // F             23.12465; ... // F#             24.49971; ... // G             25.95654];    // G#chord_table = [1 5 8; ...  // A               2 6 9; ...  // A#               3 7 10; ... // B               4 8 11; ... // C               5 9 12; ... // C#               6 10 1; ... // D               7 11 2; ... // D#               8 12 3; ... // E               9 1 4; ...  // F               10 2 5; ... // F#               11 3 6; ... // G               12 4 7];    // G#`

The unique set of notes in the note_intervals variable can now be compared against the notes in the chord table, find applicable chords.  Since only some of the notes in the chord may be detected at a time, the algorithm must be tolerate of missing notes.  This is done by first assuming that any chord could be the correct one, and then whittling away at the possibilities one by one for each detected note at each instant in time.
`(2) unique_intervals = unique(note_intervals(idx(ii),find(note_intervals(idx(ii),:) > 0)));    root_chords = 1:12;    for jj=1:length(unique_intervals)        [rr cc] = find(chord_table == unique_intervals(jj));        root_chords = intersect(root_chords, rr);    end`

The variable root_chords should now (ideally) contain one remaining chord, the correct chord for the detected notes.  If only one note is detected in a particular time interval, it is assumed that that note is the root of the chord.  The root_chord along with the underlying notes are then printed to the screen for each instant in time.  The following is a screen shot of the same time interval reported in part 2.  The underlying notes have been reduced to just the unique components.
`Time =  18.9, Chord = G  , Notes = B  G Time =  22.3, Chord = C  , Notes = E  G Time =  23.0, Chord = G  , Notes = D  G Time =  23.6, Chord = G  , Notes = G Time =  24.1, Chord = G  , Notes = B  G Time =  24.6, Chord = G  , Notes = G Time =  25.1, Chord = C  , Notes = E  G Time =  25.6, Chord = NA , Notes = A  D  E Time =  27.4, Chord = C  , Notes = E  G Time =  28.4, Chord = G  , Notes = D  G Time =  29.2, Chord = G  , Notes = B  G Time =  30.2, Chord = C  , Notes = E  G Time =  31.0, Chord = D  , Notes = A  D Time =  32.8, Chord = C  , Notes = E  G Time =  33.5, Chord = F  , Notes = A  F Time =  34.3, Chord = F  , Notes = A  F Time =  35.3, Chord = C  , Notes = E  G Time =  36.4, Chord = F  , Notes = A  F Time =  37.9, Chord = C  , Notes = C  E  G Time =  38.9, Chord = NA , Notes = A  E  F Time =  39.4, Chord = F  , Notes = A  F Time =  43.0, Chord = C  , Notes = E  G Time =  44.0, Chord = NA , Notes = A  D  E Time =  45.1, Chord = D  , Notes = A  D Time =  45.6, Chord = C  , Notes = E  G Time =  46.6, Chord = G  , Notes = D  G Time =  47.4, Chord = G  , Notes = B  G`

Note that there are several "NA"s reported for chords that could not be properly reconstructed.  Examining the underlying notes reveals an invalid interval present for the parent chord.  This could be due to natural human error in playing the guitar riff, or measurement error in the FFT from part 1.  Also note that in many cases, only two notes were detected of the three that make up the chord.  In a few cases, only one note was detected.  However, the basic chord progression of G - C - D - C - G is clearly present with the bridge of C - F - C - F visible at 33 seconds.  In the next part, we attempt to run the algorithm against a full song (guitar, bass, lyrics, drums) and make tweaks as necessary.