Changeset 29893 for main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js
- Timestamp:
- 2015-05-18T16:42:17+12:00 (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js
r29892 r29893 1 1 "use strict"; 2 2 3 // From:3 // Key detection algorithm, as described at: 4 4 // http://rnhart.net/articles/key-finding/ 5 6 // (from this web site) .... 7 // Krumhansl-Schmuckler key-finding algorithm (by Carol L. Krumhansl 8 // and Mark A. Schmuckler). The profile numbers came from experiments 9 // done by Krumhansl and Edward J. Kessler. The experiments consisted 10 // of playing a set of context tones or chords, playing a probe tone, 11 // and asking a listener to rate how well the probe tone fit with the 12 // context. You can read about the experiments and the algorithm in 13 // Krumhansl's book Cognitive Foundations of Musical Pitch. (The 14 // experiments are described in Chapter 2. The key-finding algorithm 15 // is described in Chapter 4.) You may be able to read portions of 16 // the book on Google Books. 17 18 19 function khMean(vals) 20 { 21 var len = vals.length; 22 if (len==0) { 23 return 0; 24 } 25 26 var total = 0; 27 28 for (var i=0; i<len; i++) { 29 total += vals[i]; 30 } 31 32 return total/len; 33 } 34 35 function khUnbiased(vals) 36 { 37 var unbiased_vals = []; 38 39 var len = vals.length; 40 if (len==0) { 41 return unbiased_vals; 42 } 43 44 var avg = khMean(vals); 45 46 for (var i=0; i<len; i++) { 47 unbiased_vals.push(vals[i] - avg) 48 } 49 50 return unbiased_vals; 51 } 52 53 54 function khCorrelationCoefficientUnbiased(a1,a2) 55 { 56 var a1_len = a1.length; 57 var a2_len = a2.length; 58 59 if (a1_len != a2_len) { 60 throw "khCorrelationCoefficientUnbiased(): arrays should be of the same length (" + a1_len + " vs " + a2_len + ")"; 61 } 62 var len = a1_len; 63 64 var a1_a2_pair_prod = 0; 65 var a1_square = 0; 66 var a2_square = 0; 67 68 for (var i=0; i<len; i++) { 69 a1_a2_pair_prod += (a1[i]*a2[i]); 70 a1_square += (a1[i]*a1[i]); 71 a2_square += (a2[i]*a2[i]); 72 } 73 74 return a1_a2_pair_prod / Math.sqrt(a1_square * a2_square); 75 } 76 5 77 6 78 //major profile … … 19 91 var kh_minor_profile = [6.33, 2.68, 3.52, 5.38, 2.60, 3.53, 2.54, 4.75, 3.98, 2.69, 3.34, 3.17 ]; 20 92 93 var kh_major_profile_unbiased = khUnbiased(kh_major_profile); 94 95 var kh_minor_profile_unbiased = khUnbiased(kh_minor_profile); 96 21 97 22 98 function khCreatePairing(profile,chromatic_scale_durations,offset) 23 99 { 24 var pairing = []; 25 for (var p=0; p<12; p++) { 26 pairing.push({"p":profile[p],"c":chromatic_scale_durations[(p+s)%12]}); 100 var p = []; 101 var c = []; 102 for (var i=0; i<12; i++) { 103 p.push(profile[i]) 104 c.push(chromatic_scale_durations[(i+offset)%12]); 27 105 } 28 106 29 107 30 return pairing;31 } 32 33 34 function khCreateAllPairings(chromatic_scale_durations ,major_profile,minor_profile)108 return {"p":p, "c":c}; 109 } 110 111 112 function khCreateAllPairings(chromatic_scale_durations_unbiased,major_profile_unbiased,minor_profile_unbiased) 35 113 { 36 114 // chromatic_scale_durations.length = 12 … … 45 123 var scale = chromatic_keys[s]; 46 124 47 major_pairings[scale] = khCreatePairing(major_profile ,chromatic_scale_durations,s);48 minor_pairings[scale] = khCreatePairing(minor_profile ,chromatic_scale_durations,s);125 major_pairings[scale] = khCreatePairing(major_profile_unbiased,chromatic_scale_durations_unbiased,s); 126 minor_pairings[scale] = khCreatePairing(minor_profile_unbiased,chromatic_scale_durations_unbiased,s); 49 127 } 50 128 51 129 return {"major" : major_pairings, "minor" : minor_pairings}; 52 53 } 54 55 130 } 131 132 function khComputeKeyCorrelationCoefficients(key_pairings_unbiased) 133 { 134 var correlations = {}; 135 136 var keys = Object.keys(key_pairings_unbiased); 137 var keys_len = keys.length; 138 139 for (var k=0; k<keys_len; k++) { 140 141 var key = keys[k]; 142 var key_pairing_unbiased = key_pairings_unbiased[key]; 143 144 var correlation_coeff = khCorrelationCoefficientUnbiased(key_pairing_unbiased.p,key_pairing_unbiased.c); 145 correlations[key] = correlation_coeff; 146 } 147 148 return correlations; 149 } 150 151 152 function khComputeAllCorrelationCoefficients(pairings_unbiased) 153 { 154 var major_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.major); 155 var minor_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.minor); 156 157 return {"major" : major_correlation, "minor" : minor_correlation}; 158 } 159 160 function khFindMaxCorrelation(alignments) 161 { 162 var max_val = 0; 163 var max_key = null; 164 165 var major_minor = [ "major", "minor" ]; 166 167 for (var m=0; m<major_minor.length; m++) { 168 var mm = major_minor[m]; 169 var mm_alignment = alignments[mm]; 170 171 var mm_keys = Object.keys(mm_alignment); 172 173 for (var k=0; k<mm_keys.length; k++) { 174 var key = mm_keys[k]; 175 var correlation_coeff = mm_alignment[key]; 176 if (correlation_coeff>max_val) { 177 max_val = correlation_coeff; 178 max_key = key + " (" + mm + ")"; 179 } 180 } 181 } 182 183 return { "key": max_key, "score": max_val }; 184 } 185 186 function khKeyDetection(chromatic_scale_durations) 187 { 188 // Work out durations of MIDI events folded into octave (60=Middle-C) 189 // (unbiased data) 190 191 //var chromatic_scale_durations = [ 432, 231, 0, 405, 12, 316, 4, 126, 612, 0, 191, 1]; 192 var chromatic_scale_durations_unbiased = khUnbiased(chromatic_scale_durations); 193 194 // Generate all (unbiased) pairings 195 var kh_pairings_unbiased = khCreateAllPairings(chromatic_scale_durations_unbiased,kh_major_profile_unbiased,kh_minor_profile_unbiased) 196 197 // Compute Correlation Coefficients 198 var kh_alignments = khComputeAllCorrelationCoefficients(kh_pairings_unbiased); 199 200 // Pick highest values 201 202 var strongest_profile = khFindMaxCorrelation(kh_alignments); 203 204 console.log("Predicted Key: " + JSON.stringify(strongest_profile)); 205 206 return strongest_profile; 207 208 } 209 210
Note:
See TracChangeset
for help on using the changeset viewer.