changeset 174:d22f69c2b025

Merge new tag
author Chris Cannam
date Mon, 02 Nov 2015 12:35:13 +0000
parents d95c4cdef8af (diff) 5190d4947ad9 (current diff)
children 259ef0f4622b
files .hgtags
diffstat 23 files changed, 747 insertions(+), 1019 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Nov 02 12:23:00 2015 +0000
+++ b/.hgtags	Mon Nov 02 12:35:13 2015 +0000
@@ -1,4 +1,9 @@
 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1
 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1
 dab7e7bfeba17478fa6c5af050c6270026ad635b 0.2
+2cd99c0810f28abe2fcbf2c50a29fee20b910ae4 mirex2013
 9d81703dcf6e6ac9f266b50a99dcc45448d381f9 v0.2.1
+9e9267d6d78a8e67f2a4dc1aac4ea1aab135f4f0 v1.0
+0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1
+0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1
+ba9310bcc3fcb3c58c99d25837b6f62662666b7d v1.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CITATION	Mon Nov 02 12:35:13 2015 +0000
@@ -0,0 +1,6 @@
+@inproceedings{matthias2010a,
+  author = {Matthias Mauch and Simon Dixon},
+  title = {Approximate Note Transcription for the Improved Identification of Difficult Chords},
+  booktitle = {Proceedings of the 11th International Society for Music Information Retrieval Conference (ISMIR 2010)},
+  year = {2010}
+} 
--- a/Chordino.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/Chordino.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -36,8 +36,6 @@
     m_chordnames(0)    
 {
     if (debug_on) cerr << "--> Chordino" << endl;
-    // get the *chord* dictionary from file (if the file exists)
-    
 }
 
 Chordino::~Chordino()
@@ -63,7 +61,7 @@
 Chordino::getDescription() const
 {
     if (debug_on) cerr << "--> getDescription" << endl;
-    return "Chordino provides a simple chord transcription based on NNLS Chroma (as in the NNLS Chroma plugin). Chord profiles given by the user in the file chord.dict are used to calculate frame-wise chord similarities. Two simple (non-state-of-the-art!) algorithms are available that smooth these to provide a chord transcription: a simple chord change method, and a standard HMM/Viterbi approach.";
+    return "Chordino provides a simple chord transcription based on NNLS Chroma (as in the NNLS Chroma plugin). Chord profiles given by the user in the file chord.dict are used to calculate frame-wise chord similarities. A simple (non-state-of-the-art!) algorithm smooths these to provide a chord transcription using a standard HMM/Viterbi approach.";
 }
 
 Chordino::ParameterList
@@ -72,89 +70,91 @@
     if (debug_on) cerr << "--> getParameterDescriptors" << endl;
     ParameterList list;
 
-    ParameterDescriptor d;
-    d.identifier = "useNNLS";
-    d.name = "use approximate transcription (NNLS)";
-    d.description = "Toggles approximate transcription (NNLS).";
-    d.unit = "";
-    d.minValue = 0.0;
-    d.maxValue = 1.0;
-    d.defaultValue = 1.0;
-    d.isQuantized = true;
-	d.quantizeStep = 1.0;
-    list.push_back(d);
+    ParameterDescriptor useNNLSParam;
+    useNNLSParam.identifier = "useNNLS";
+    useNNLSParam.name = "use approximate transcription (NNLS)";
+    useNNLSParam.description = "Toggles approximate transcription (NNLS).";
+    useNNLSParam.unit = "";
+    useNNLSParam.minValue = 0.0;
+    useNNLSParam.maxValue = 1.0;
+    useNNLSParam.defaultValue = 1.0;
+    useNNLSParam.isQuantized = true;
+	useNNLSParam.quantizeStep = 1.0;
+    list.push_back(useNNLSParam);
 
-    ParameterDescriptor d4;
-    d4.identifier = "useHMM";
-    d4.name = "HMM (Viterbi decoding)";
-    d4.description = "Turns on Viterbi decoding (when off, the simple chord estimator is used).";
-    d4.unit = "";
-    d4.minValue = 0.0;
-    d4.maxValue = 1.0;
-    d4.defaultValue = 1.0;
-    d4.isQuantized = true;
-	d4.quantizeStep = 1.0;
-    list.push_back(d4);
+    ParameterDescriptor rollonParam;
+    rollonParam.identifier = "rollon";
+    rollonParam.name = "bass noise threshold";
+    rollonParam.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed.";
+    rollonParam.unit = "%";
+    rollonParam.minValue = 0;
+    rollonParam.maxValue = 5;
+    rollonParam.defaultValue = 0.0;
+    rollonParam.isQuantized = true;
+	rollonParam.quantizeStep = 0.5;
+    list.push_back(rollonParam);
 
-    ParameterDescriptor d0;
-    d0.identifier = "rollon";
-    d0.name = "spectral roll-on";
-    d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed.";
-    d0.unit = "%";
-    d0.minValue = 0;
-    d0.maxValue = 5;
-    d0.defaultValue = 0.0;
-    d0.isQuantized = true;
-	d0.quantizeStep = 0.5;
-    list.push_back(d0);
+    ParameterDescriptor tuningmodeParam;
+    tuningmodeParam.identifier = "tuningmode";
+    tuningmodeParam.name = "tuning mode";
+    tuningmodeParam.description = "Tuning can be performed locally or on the whole extraction segment. Local tuning is only advisable when the tuning is likely to change over the audio, for example in podcasts, or in a cappella singing.";
+    tuningmodeParam.unit = "";
+    tuningmodeParam.minValue = 0;
+    tuningmodeParam.maxValue = 1;
+    tuningmodeParam.defaultValue = 0.0;
+    tuningmodeParam.isQuantized = true;
+    tuningmodeParam.valueNames.push_back("global tuning");
+    tuningmodeParam.valueNames.push_back("local tuning");
+    tuningmodeParam.quantizeStep = 1.0;
+    list.push_back(tuningmodeParam);
 
-    ParameterDescriptor d1;
-    d1.identifier = "tuningmode";
-    d1.name = "tuning mode";
-    d1.description = "Tuning can be performed locally or on the whole extraction segment. Local tuning is only advisable when the tuning is likely to change over the audio, for example in podcasts, or in a cappella singing.";
-    d1.unit = "";
-    d1.minValue = 0;
-    d1.maxValue = 1;
-    d1.defaultValue = 0.0;
-    d1.isQuantized = true;
-    d1.valueNames.push_back("global tuning");
-    d1.valueNames.push_back("local tuning");
-    d1.quantizeStep = 1.0;
-    list.push_back(d1);
+    ParameterDescriptor whiteningParam;
+    whiteningParam.identifier = "whitening";
+    whiteningParam.name = "spectral whitening";
+    whiteningParam.description = "Spectral whitening: no whitening - 0; whitening - 1.";
+    whiteningParam.unit = "";
+    whiteningParam.isQuantized = true;
+    whiteningParam.minValue = 0.0;
+    whiteningParam.maxValue = 1.0;
+    whiteningParam.defaultValue = 1.0;
+    whiteningParam.isQuantized = false;
+    list.push_back(whiteningParam);
 
-    ParameterDescriptor d2;
-    d2.identifier = "whitening";
-    d2.name = "spectral whitening";
-    d2.description = "Spectral whitening: no whitening - 0; whitening - 1.";
-    d2.unit = "";
-    d2.isQuantized = true;
-    d2.minValue = 0.0;
-    d2.maxValue = 1.0;
-    d2.defaultValue = 1.0;
-    d2.isQuantized = false;
-    list.push_back(d2);
+    ParameterDescriptor spectralShapeParam;
+    spectralShapeParam.identifier = "s";
+    spectralShapeParam.name = "spectral shape";
+    spectralShapeParam.description = "Determines how individual notes in the note dictionary look: higher values mean more dominant higher harmonics.";
+    spectralShapeParam.unit = "";
+    spectralShapeParam.minValue = 0.5;
+    spectralShapeParam.maxValue = 0.9;
+    spectralShapeParam.defaultValue = 0.7;
+    spectralShapeParam.isQuantized = false;
+    list.push_back(spectralShapeParam);
 
-    ParameterDescriptor d3;
-    d3.identifier = "s";
-    d3.name = "spectral shape";
-    d3.description = "Determines how individual notes in the note dictionary look: higher values mean more dominant higher harmonics.";
-    d3.unit = "";
-    d3.minValue = 0.5;
-    d3.maxValue = 0.9;
-    d3.defaultValue = 0.7;
-    d3.isQuantized = false;
-    list.push_back(d3);
+    ParameterDescriptor boostnParam;
+    boostnParam.identifier = "boostn";
+    boostnParam.name = "boost N";
+    boostnParam.description = "Boost likelihood of the N (no chord) label.";
+    boostnParam.unit = "";
+    boostnParam.minValue = 0.0;
+    boostnParam.maxValue = 1.0;
+    boostnParam.defaultValue = 0.1;
+    boostnParam.isQuantized = false;
+    list.push_back(boostnParam);
 
-    ParameterDescriptor boostn;
-    boostn.identifier = "boostn";
-    boostn.name = "boost N";
-    boostn.description = "Boost likelihood of the N (no chord) label.";
-    boostn.unit = "";
-    boostn.minValue = 0.0;
-    boostn.maxValue = 1.0;
-    boostn.defaultValue = 0.1;
-    boostn.isQuantized = false;
-    list.push_back(boostn);
+    ParameterDescriptor usehartesyntaxParam;
+    usehartesyntaxParam.identifier = "usehartesyntax";
+    usehartesyntaxParam.name = "use Harte syntax";
+    usehartesyntaxParam.description = "Use the chord syntax proposed by Harte";
+    usehartesyntaxParam.unit = "";
+    usehartesyntaxParam.minValue = 0.0;
+    usehartesyntaxParam.maxValue = 1.0;
+    usehartesyntaxParam.defaultValue = 0.0;
+    usehartesyntaxParam.isQuantized = true;
+	usehartesyntaxParam.quantizeStep = 1.0;
+	usehartesyntaxParam.valueNames.push_back("no");
+    usehartesyntaxParam.valueNames.push_back("yes");
+    list.push_back(usehartesyntaxParam);
 
     return list;
 }
@@ -167,10 +167,13 @@
     
     int index = 0;
 
+    float featureRate =
+        (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
+    
     OutputDescriptor d7;
     d7.identifier = "simplechord";
     d7.name = "Chord Estimate";
-    d7.description = "Estimated chord times and labels. Two simple (non-state-of-the-art!) algorithms are available that smooth these to provide a chord transcription: a simple chord change method, and a standard HMM/Viterbi approach.";
+    d7.description = "Estimated chord times and labels.";
     d7.unit = "";
     d7.hasFixedBinCount = true;
     d7.binCount = 0;
@@ -178,14 +181,14 @@
     d7.isQuantized = false;
     d7.sampleType = OutputDescriptor::VariableSampleRate;
     d7.hasDuration = false;
-    d7.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
+    d7.sampleRate = featureRate;
     list.push_back(d7);
     m_outputChords = index++;
     
     OutputDescriptor chordnotes;
     chordnotes.identifier = "chordnotes";
     chordnotes.name = "Note Representation of Chord Estimate";
-    chordnotes.description = "A simple represenation of the estimated chord with bass note (if applicable) and chord notes.";
+    chordnotes.description = "A simple representation of the estimated chord with bass note (if applicable) and chord notes.";
     chordnotes.unit = "MIDI units";
     chordnotes.hasFixedBinCount = true;
     chordnotes.binCount = 1;
@@ -196,7 +199,7 @@
     chordnotes.quantizeStep = 1;
     chordnotes.sampleType = OutputDescriptor::VariableSampleRate;
     chordnotes.hasDuration = true;
-    chordnotes.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
+    chordnotes.sampleRate = featureRate;
     list.push_back(chordnotes);
     m_outputChordnotes = index++;
     
@@ -208,15 +211,28 @@
     d8.hasFixedBinCount = true;
     d8.binCount = 1;
     d8.hasKnownExtents = false;
-    // d8.minValue = 0.0;
-    // d8.maxValue = 0.999;
     d8.isQuantized = false;
     d8.sampleType = OutputDescriptor::FixedSampleRate;
+    d8.sampleRate = featureRate;
     d8.hasDuration = false;
-    // d8.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
     list.push_back(d8);
     m_outputHarmonicChange = index++;
   
+    OutputDescriptor loglikelihood;
+    loglikelihood.identifier = "loglikelihood";
+    loglikelihood.name = "Log-Likelihood of Chord Estimate";
+    loglikelihood.description = "Logarithm of the likelihood value of the simple chord estimate.";
+    loglikelihood.unit = "";
+    loglikelihood.hasFixedBinCount = true;
+    loglikelihood.binCount = 1;
+    loglikelihood.hasKnownExtents = false;
+    loglikelihood.isQuantized = false;
+    loglikelihood.sampleType = OutputDescriptor::FixedSampleRate;
+    loglikelihood.sampleRate = featureRate;
+    loglikelihood.hasDuration = false;
+    list.push_back(loglikelihood);
+    m_outputLoglikelihood = index++;
+  
     return list;
 }
 
@@ -230,7 +246,7 @@
     if (!NNLSBase::initialise(channels, stepSize, blockSize)) {
         return false;
     }
-    m_chordnames = chordDictionary(&m_chorddict, &m_chordnotes, m_boostN);
+    m_chordnames = chordDictionary(&m_chorddict, &m_chordnotes, m_boostN, m_harte_syntax);
     return true;
 }
 
@@ -284,12 +300,8 @@
         calculate a tuned log-frequency spectrogram (currentTunedSpec): use the tuning estimated above (kinda f0) to 
         perform linear interpolation on the existing log-frequency spectrogram (kinda currentLogSpectrum).
     **/
-    cerr << endl << "[Chordino Plugin] Tuning Log-Frequency Spectrogram ... ";
+    if (debug_on) cerr << endl << "[Chordino Plugin] Tuning Log-Frequency Spectrogram ... ";
 					
-    float tempValue = 0;
-    float dbThreshold = 0; // relative to the background spectrum
-    float thresh = pow(10,dbThreshold/20);
-    // cerr << "tune local ? " << m_tuneLocal << endl;
     int count = 0;
 		
     FeatureList tunedSpec;
@@ -313,7 +325,7 @@
         // cerr << intShift << " " << floatShift << endl;
 		        
         for (int k = 2; k < (int)currentLogSpectrum.values.size() - 3; ++k) { // interpolate all inner bins
-            tempValue = currentLogSpectrum.values[k + intShift] * (1-floatShift) + currentLogSpectrum.values[k+intShift+1] * floatShift;
+            float tempValue = currentLogSpectrum.values[k + intShift] * (1-floatShift) + currentLogSpectrum.values[k+intShift+1] * floatShift;
             currentTunedSpec.values.push_back(tempValue);
         }
 		        
@@ -339,7 +351,7 @@
         tunedSpec.push_back(currentTunedSpec);
         count++;
     }
-    cerr << "done." << endl;
+    if (debug_on) cerr << "done." << endl;
 	    
     /** Semitone spectrum and chromagrams
         Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum
@@ -348,9 +360,9 @@
         bass and treble stacked onto each other).
     **/
     if (m_useNNLS == 0) {
-        cerr << "[Chordino Plugin] Mapping to semitone spectrum and chroma ... ";
+        if (debug_on) cerr << "[Chordino Plugin] Mapping to semitone spectrum and chroma ... ";
     } else {
-        cerr << "[Chordino Plugin] Performing NNLS and mapping to chroma ... ";
+        if (debug_on) cerr << "[Chordino Plugin] Performing NNLS and mapping to chroma ... ";
     }
 
 	    
@@ -361,7 +373,7 @@
 
     FeatureList chromaList;
     
-    
+    bool clipwarned = false;
 
     for (FeatureList::iterator it = tunedSpec.begin(); it != tunedSpec.end(); ++it) {
         Feature currentTunedSpec = *it; // logfreq spectrum
@@ -442,7 +454,7 @@
         vector<float> origchroma = chroma;
         chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas 
         currentChromas.values = chroma;
- 
+
         if (m_doNormalizeChroma > 0) {
             vector<float> chromanorm = vector<float>(3,0);			
             switch (int(m_doNormalizeChroma)) {
@@ -482,15 +494,22 @@
         for (int iChord = 0; iChord < nChord; iChord++) {
             tempchordvalue = 0;
             for (int iBin = 0; iBin < 12; iBin++) {
-                tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin];                
+                tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin];
             }
             for (int iBin = 12; iBin < 24; iBin++) {
                 tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin];
             }
             if (iChord == nChord-1) tempchordvalue *= .7;
             if (tempchordvalue < 0) tempchordvalue = 0.0;
-            tempchordvalue = pow(1.3,tempchordvalue);
-            sumchordvalue+=tempchordvalue;
+            if (tempchordvalue > 200.0) {
+                if (!clipwarned) {
+                    cerr << "WARNING: interim chroma contains extreme chord value " << tempchordvalue << ", clipping this and any others that appear" << endl;
+                    clipwarned = true;
+                }
+                tempchordvalue = 200.0;
+            }
+            tempchordvalue = pow(1.3, tempchordvalue);
+            sumchordvalue += tempchordvalue;
             currentChordSalience.push_back(tempchordvalue);
         }
         if (sumchordvalue > 0) {
@@ -504,234 +523,83 @@
 	        
         count++;
     }
-    cerr << "done." << endl;
+    if (debug_on) cerr << "done." << endl;
 		
     vector<Feature> oldnotes;
 
-    // bool m_useHMM = true; // this will go into the chordino header file.
-	if (m_useHMM == 1.0) {
-        cerr << "[Chordino Plugin] HMM Chord Estimation ... ";
-        int oldchord = nChord-1;
-        double selftransprob = 0.99;
-	    
-        // vector<double> init = vector<double>(nChord,1.0/nChord);
-        vector<double> init = vector<double>(nChord,0); init[nChord-1] = 1;
-        
-        double *delta;
-        delta = (double *)malloc(sizeof(double)*nFrame*nChord);                
-        
-        vector<vector<double> > trans;
-        for (int iChord = 0; iChord < nChord; iChord++) {
-            vector<double> temp = vector<double>(nChord,(1-selftransprob)/(nChord-1));            
-            temp[iChord] = selftransprob;
-            trans.push_back(temp);
-        }
-        vector<int> chordpath = ViterbiPath(init, trans, chordogram, delta);
-
-
-        Feature chord_feature; // chord estimate
-        chord_feature.hasTimestamp = true;
-        chord_feature.timestamp = timestamps[0];
-        chord_feature.label = m_chordnames[chordpath[0]];
-        fsOut[m_outputChords].push_back(chord_feature);
-        
-        chordchange[0] = 0;
-        for (int iFrame = 1; iFrame < (int)chordpath.size(); ++iFrame) {
-            // cerr << chordpath[iFrame] << endl;
-            if (chordpath[iFrame] != oldchord ) {
-                // chord
-                Feature chord_feature; // chord estimate
-                chord_feature.hasTimestamp = true;
-                chord_feature.timestamp = timestamps[iFrame];
-                chord_feature.label = m_chordnames[chordpath[iFrame]];
-                fsOut[m_outputChords].push_back(chord_feature);
-                oldchord = chordpath[iFrame];         
-                // chord notes
-                for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord
-                    oldnotes[iNote].duration = oldnotes[iNote].duration + timestamps[iFrame];
-                    fsOut[m_outputChordnotes].push_back(oldnotes[iNote]);
-                }
-                oldnotes.clear();
-                for (int iNote = 0; iNote < (int)m_chordnotes[chordpath[iFrame]].size(); ++iNote) { // prepare notes of current chord
-                    Feature chordnote_feature;
-                    chordnote_feature.hasTimestamp = true;
-                    chordnote_feature.timestamp = timestamps[iFrame];
-                    chordnote_feature.values.push_back(m_chordnotes[chordpath[iFrame]][iNote]);
-                    chordnote_feature.hasDuration = true;
-                    chordnote_feature.duration = -timestamps[iFrame]; // this will be corrected at the next chord
-                    oldnotes.push_back(chordnote_feature);
-                }
+    if (debug_on) cerr << "[Chordino Plugin] HMM Chord Estimation ... ";
+    int oldchord = nChord-1;
+    double selftransprob = 0.99;
+ 
+    // vector<double> init = vector<double>(nChord,1.0/nChord);
+    vector<double> init = vector<double>(nChord,0); init[nChord-1] = 1;
+    
+    double *delta;
+    delta = (double *)malloc(sizeof(double)*nFrame*nChord);                
+    
+    vector<vector<double> > trans;
+    for (int iChord = 0; iChord < nChord; iChord++) {
+        vector<double> temp = vector<double>(nChord,(1-selftransprob)/(nChord-1));            
+        temp[iChord] = selftransprob;
+        trans.push_back(temp);
+    }
+    vector<double> scale;
+    vector<int> chordpath = ViterbiPath(init, trans, chordogram, delta, &scale);
+    
+    Feature chord_feature; // chord estimate
+    chord_feature.hasTimestamp = true;
+    chord_feature.timestamp = timestamps[0];
+    chord_feature.label = m_chordnames[chordpath[0]];
+    fsOut[m_outputChords].push_back(chord_feature);
+    
+    chordchange[0] = 0;
+    for (int iFrame = 1; iFrame < (int)chordpath.size(); ++iFrame) {
+        if (chordpath[iFrame] != oldchord ) {
+            // chord
+            Feature chord_feature; // chord estimate
+            chord_feature.hasTimestamp = true;
+            chord_feature.timestamp = timestamps[iFrame];
+            chord_feature.label = m_chordnames[chordpath[iFrame]];
+            fsOut[m_outputChords].push_back(chord_feature);
+            oldchord = chordpath[iFrame];         
+            // chord notes
+            for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord
+                oldnotes[iNote].duration = oldnotes[iNote].duration + timestamps[iFrame];
+                fsOut[m_outputChordnotes].push_back(oldnotes[iNote]);
             }
-            /* calculating simple chord change prob */            
-            for (int iChord = 0; iChord < nChord; iChord++) {
-                chordchange[iFrame-1] += delta[(iFrame-1)*nChord + iChord] * log(delta[(iFrame-1)*nChord + iChord]/delta[iFrame*nChord + iChord]);
+            oldnotes.clear();
+            for (int iNote = 0; iNote < (int)m_chordnotes[chordpath[iFrame]].size(); ++iNote) { // prepare notes of current chord
+                Feature chordnote_feature;
+                chordnote_feature.hasTimestamp = true;
+                chordnote_feature.timestamp = timestamps[iFrame];
+                chordnote_feature.values.push_back(m_chordnotes[chordpath[iFrame]][iNote]);
+                chordnote_feature.hasDuration = true;
+                chordnote_feature.duration = -timestamps[iFrame]; // this will be corrected at the next chord
+                oldnotes.push_back(chordnote_feature);
             }
         }
-        
-        // cerr << chordpath[0] << endl;
-	} else {
-        /* Simple chord estimation
-           I just take the local chord estimates ("currentChordSalience") and average them over time, then
-           take the maximum. Very simple, don't do this at home...
-        */
-        cerr << "[Chordino Plugin] Simple Chord Estimation ... ";
-        count = 0; 
-        int halfwindowlength = m_inputSampleRate / m_stepSize;
-        vector<int> chordSequence;
-        for (vector<Vamp::RealTime>::iterator it = timestamps.begin(); it != timestamps.end(); ++it) { // initialise the score chordogram
-            vector<int> temp = vector<int>(nChord,0);
-            scoreChordogram.push_back(temp);
-        }
-        for (vector<Vamp::RealTime>::iterator it = timestamps.begin(); it < timestamps.end()-2*halfwindowlength-1; ++it) {		
-            int startIndex = count + 1;
-            int endIndex = count + 2 * halfwindowlength;
-
-            float chordThreshold = 2.5/nChord;//*(2*halfwindowlength+1);
-
-            vector<int> chordCandidates;
-            for (int iChord = 0; iChord+1 < nChord; iChord++) {
-                // float currsum = 0;
-                // for (int iFrame = startIndex; iFrame < endIndex; ++iFrame) {
-                //  currsum += chordogram[iFrame][iChord];
-                // }
-                //                 if (currsum > chordThreshold) chordCandidates.push_back(iChord);
-                for (int iFrame = startIndex; iFrame < endIndex; ++iFrame) {
-                    if (chordogram[iFrame][iChord] > chordThreshold) {
-                        chordCandidates.push_back(iChord);
-                        break;
-                    }                    
-                }
-            }
-            chordCandidates.push_back(nChord-1);
-            // cerr << chordCandidates.size() << endl;          
-
-            float maxval = 0; // will be the value of the most salient *chord change* in this frame
-            float maxindex = 0; //... and the index thereof
-            int bestchordL = nChord-1; // index of the best "left" chord
-            int bestchordR = nChord-1; // index of the best "right" chord
-
-            for (int iWF = 1; iWF < 2*halfwindowlength; ++iWF) {
-                // now find the max values on both sides of iWF
-                // left side:
-                float maxL = 0;
-                int maxindL = nChord-1;
-                for (int kChord = 0; kChord < (int)chordCandidates.size(); kChord++) {
-                    int iChord = chordCandidates[kChord];
-                    float currsum = 0;
-                    for (int iFrame = 0; iFrame < iWF-1; ++iFrame) {
-                        currsum += chordogram[count+iFrame][iChord];
-                    }
-                    if (iChord == nChord-1) currsum *= 0.8;
-                    if (currsum > maxL) {
-                        maxL = currsum;
-                        maxindL = iChord;
-                    }
-                }				
-                // right side:
-                float maxR = 0;
-                int maxindR = nChord-1;
-                for (int kChord = 0; kChord < (int)chordCandidates.size(); kChord++) {
-                    int iChord = chordCandidates[kChord];
-                    float currsum = 0;
-                    for (int iFrame = iWF-1; iFrame < 2*halfwindowlength; ++iFrame) {
-                        currsum += chordogram[count+iFrame][iChord];
-                    }
-                    if (iChord == nChord-1) currsum *= 0.8;
-                    if (currsum > maxR) {
-                        maxR = currsum;
-                        maxindR = iChord;
-                    }
-                }
-                if (maxL+maxR > maxval) {					
-                    maxval = maxL+maxR;
-                    maxindex = iWF;
-                    bestchordL = maxindL;
-                    bestchordR = maxindR;
-                }
-
-            }
-            // cerr << "maxindex: " << maxindex << ", bestchordR is " << bestchordR << ", of frame " << count << endl;
-            // add a score to every chord-frame-point that was part of a maximum 
-            for (int iFrame = 0; iFrame < maxindex-1; ++iFrame) {
-                scoreChordogram[iFrame+count][bestchordL]++;
-            }
-            for (int iFrame = maxindex-1; iFrame < 2*halfwindowlength; ++iFrame) {
-                scoreChordogram[iFrame+count][bestchordR]++;
-            }
-            if (bestchordL != bestchordR) {
-                chordchange[maxindex+count] += (halfwindowlength - abs(maxindex-halfwindowlength)) * 2.0 / halfwindowlength;
-            }
-            count++;	
-        }
-        // cerr << "*******  agent finished   *******" << endl;
-        count = 0;
-        for (vector<Vamp::RealTime>::iterator it = timestamps.begin(); it != timestamps.end(); ++it) { 
-            float maxval = 0; // will be the value of the most salient chord in this frame
-            float maxindex = 0; //... and the index thereof
-            for (int iChord = 0; iChord < nChord; iChord++) {
-                if (scoreChordogram[count][iChord] > maxval) {
-                    maxval = scoreChordogram[count][iChord];
-                    maxindex = iChord;
-                    // cerr << iChord << endl;
-                }
-            }
-            chordSequence.push_back(maxindex);    
-            count++;
-        }
-
-
-        // mode filter on chordSequence
-        count = 0;
-        string oldChord = "";
-        for (vector<Vamp::RealTime>::iterator it = timestamps.begin(); it != timestamps.end(); ++it) {
-            Feature chord_feature; // chord estimate
-            chord_feature.hasTimestamp = true;
-            chord_feature.timestamp = *it;
-            // Feature currentChord; // chord estimate
-            // currentChord.hasTimestamp = true;
-            // currentChord.timestamp = currentChromas.timestamp;
-
-            vector<int> chordCount = vector<int>(nChord,0);
-            int maxChordCount = 0;
-            int maxChordIndex = nChord-1;
-            string maxChord;
-            int startIndex = max(count - halfwindowlength/2,0);
-            int endIndex = min(int(chordogram.size()), count + halfwindowlength/2);
-            for (int i = startIndex; i < endIndex; i++) {				
-                chordCount[chordSequence[i]]++;
-                if (chordCount[chordSequence[i]] > maxChordCount) {
-                    // cerr << "start index " << startIndex << endl;
-                    maxChordCount++;
-                    maxChordIndex = chordSequence[i];
-                    maxChord = m_chordnames[maxChordIndex];
-                }
-            }
-            // chordSequence[count] = maxChordIndex;
-            // cerr << maxChordIndex << endl;
-            // cerr << chordchange[count] << endl;            
-            if (oldChord != maxChord) {
-                oldChord = maxChord;
-                chord_feature.label = m_chordnames[maxChordIndex];
-                fsOut[m_outputChords].push_back(chord_feature);
-                for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord
-                    oldnotes[iNote].duration = oldnotes[iNote].duration + chord_feature.timestamp;
-                    fsOut[m_outputChordnotes].push_back(oldnotes[iNote]);
-                }
-                oldnotes.clear();
-                for (int iNote = 0; iNote < (int)m_chordnotes[maxChordIndex].size(); ++iNote) { // prepare notes of current chord
-                    Feature chordnote_feature;
-                    chordnote_feature.hasTimestamp = true;
-                    chordnote_feature.timestamp = chord_feature.timestamp;
-                    chordnote_feature.values.push_back(m_chordnotes[maxChordIndex][iNote]);
-                    chordnote_feature.hasDuration = true;
-                    chordnote_feature.duration = -chord_feature.timestamp; // this will be corrected at the next chord
-                    oldnotes.push_back(chordnote_feature);
-                }
-            }
-            count++;
+        /* calculating simple chord change prob */            
+        for (int iChord = 0; iChord < nChord; iChord++) {
+            double num = delta[(iFrame-1) * nChord + iChord];
+            double denom = delta[iFrame * nChord + iChord];
+            double eps = 1e-7;
+            if (denom < eps) denom = eps;
+            chordchange[iFrame-1] += num * log(num / denom + eps);
         }
     }
-    Feature chord_feature; // last chord estimate
+    
+    float logscale = 0;
+    for (int iFrame = 0; iFrame < nFrame; ++iFrame) {
+        logscale -= log(scale[iFrame]);
+        Feature loglikelihood;
+        loglikelihood.hasTimestamp = true;
+        loglikelihood.timestamp = timestamps[iFrame];
+        loglikelihood.values.push_back(-log(scale[iFrame]));
+        // cerr << chordchange[iFrame] << endl;
+        fsOut[m_outputLoglikelihood].push_back(loglikelihood);
+    }
+    logscale /= nFrame;
+
     chord_feature.hasTimestamp = true;
     chord_feature.timestamp = timestamps[timestamps.size()-1];
     chord_feature.label = "N";
@@ -742,19 +610,20 @@
         fsOut[m_outputChordnotes].push_back(oldnotes[iNote]);
     }
     
-    cerr << "done." << endl;
-    
+    if (debug_on) cerr << "done." << endl;
+
     for (int iFrame = 0; iFrame < nFrame; iFrame++) {
         Feature chordchange_feature;
         chordchange_feature.hasTimestamp = true;
         chordchange_feature.timestamp = timestamps[iFrame];
         chordchange_feature.values.push_back(chordchange[iFrame]);
-        // cerr << chordchange[iFrame] << endl;
+//        cerr << "putting value " << chordchange[iFrame] << " at time " << chordchange_feature.timestamp << endl;
         fsOut[m_outputHarmonicChange].push_back(chordchange_feature);
     }
+
+    free(delta);
     
     // for (int iFrame = 0; iFrame < nFrame; iFrame++) cerr << fsOut[m_outputHarmonicChange][iFrame].values[0] << endl;
     
-    
     return fsOut;     
 }
--- a/Chordino.h	Mon Nov 02 12:23:00 2015 +0000
+++ b/Chordino.h	Mon Nov 02 12:35:13 2015 +0000
@@ -48,6 +48,7 @@
     mutable int m_outputChords;
     mutable int m_outputChordnotes;
     mutable int m_outputHarmonicChange;
+    mutable int m_outputLoglikelihood;
     vector<float> m_chorddict;
     vector<vector<int> > m_chordnotes;
     vector<string> m_chordnames;
--- a/Makefile.linux	Mon Nov 02 12:23:00 2015 +0000
+++ b/Makefile.linux	Mon Nov 02 12:35:13 2015 +0000
@@ -1,39 +1,34 @@
-
-PLUGIN_LIBRARY_NAME = nnls-chroma
-
-PLUGIN_CODE_OBJECTS = chromamethods.o NNLSBase.o NNLSChroma.o Chordino.o Tuning.o plugins.o nnls.o viterbi.o
-
-VAMP_SDK_DIR = ../vamp-plugin-sdk
-
-
-ARCHFLAGS = -O3 -ftree-vectorize -ffast-math
-#ARCHFLAGS = -g
-
-CFLAGS = $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC
-CXXFLAGS = $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC
-PLUGIN_EXT = .so
-PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
-LDFLAGS = -shared -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--version-script=vamp-plugin.map 
-
-
-$(PLUGIN): $(PLUGIN_CODE_OBJECTS)
-	   $(CXX) -o $@ $^ $(LDFLAGS)
-
-nnls.o:	nnls.c		# not nnls.f
-
-clean:
-	rm -f *.o
-
-# DO NOT DELETE
-
-nnls.o: nnls.h
-Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h
-chromamethods.o: chromamethods.h nnls.h chorddict.cpp
-NNLSBase.o: NNLSBase.h chromamethods.h nnls.h
-NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h
-plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h
-Tuning.o: Tuning.h NNLSBase.h chromamethods.h nnls.h
-Chordino.o: NNLSBase.h
-chromamethods.o: nnls.h
-NNLSChroma.o: NNLSBase.h
-Tuning.o: NNLSBase.h
+
+PLUGIN_LIBRARY_NAME = nnls-chroma
+
+PLUGIN_CODE_OBJECTS = chromamethods.o NNLSBase.o NNLSChroma.o Chordino.o Tuning.o plugins.o nnls.o viterbi.o
+
+VAMP_SDK_DIR = ../vamp-plugin-sdk
+
+ARCHFLAGS = -O3 -ftree-vectorize -ffast-math
+#ARCHFLAGS = -g
+
+CFLAGS += $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC
+CXXFLAGS += $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC
+PLUGIN_EXT = .so
+PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
+LDFLAGS += -shared -Wl,-soname=$(PLUGIN) -L$(VAMP_SDK_DIR) -lvamp-sdk -Wl,--version-script=vamp-plugin.map 
+
+
+$(PLUGIN): $(PLUGIN_CODE_OBJECTS)
+	   $(CXX) -o $@ $^ $(LDFLAGS)
+
+nnls.o:	nnls.c		# not nnls.f
+
+clean:
+	rm -f *.o
+
+# DO NOT DELETE
+
+Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h viterbi.h
+chromamethods.o: chromamethods.h nnls.h
+NNLSBase.o: NNLSBase.h chromamethods.h nnls.h
+NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h
+plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h
+Tuning.o: Tuning.h NNLSBase.h chromamethods.h nnls.h
+viterbi.o: viterbi.h
--- a/Makefile.mingw	Mon Nov 02 12:23:00 2015 +0000
+++ b/Makefile.mingw	Mon Nov 02 12:35:13 2015 +0000
@@ -5,23 +5,25 @@
 
 VAMP_SDK_DIR = ../vamp-plugin-sdk
 
-CC=gcc
-CXX=g++
+# Allow the invoker to specify a particular set of tools through
+# TOOLPREFIX, e.g. for cross-compile
+CC=$(TOOLPREFIX)gcc
+CXX=$(TOOLPREFIX)g++
 
 OPTFLAGS = -O2 -ffast-math
 
-CFLAGS = $(OPTFLAGS) -I$(VAMP_SDK_DIR) -Wall 
-CXXFLAGS = $(OPTFLAGS) -I$(VAMP_SDK_DIR) -I../boost_1_44_0 -Wall
+CFLAGS += $(OPTFLAGS) -I$(VAMP_SDK_DIR) -Wall 
+CXXFLAGS += $(OPTFLAGS) -I$(VAMP_SDK_DIR) -I../boost_1_44_0 -Wall
 
 PLUGIN_EXT = .dll
 PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
 
-LDFLAGS = -shared -fno-exceptions -static-libgcc -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--version-script=vamp-plugin.map 
+LDFLAGS += -shared -static -fno-exceptions -static-libgcc -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--retain-symbols-file=vamp-plugin.list
 
 
 $(PLUGIN): $(PLUGIN_CODE_OBJECTS)
 	   $(CXX) -o $@ $^ $(LDFLAGS)
 
 clean:
-	del *.o
+	$(RM) *.o
 
--- a/Makefile.osx	Mon Nov 02 12:23:00 2015 +0000
+++ b/Makefile.osx	Mon Nov 02 12:35:13 2015 +0000
@@ -8,16 +8,16 @@
 # project directory
 #
 VAMP_SDK_DIR = ../vamp-plugin-sdk
-BOOST_ROOT = ../boost_1_44_0
+BOOST_ROOT = ../boost_1_48_0
 
 
 ##  Uncomment these for an OS/X native build using command-line tools:
-ARCHFLAGS = -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 -arch i386
-CFLAGS = $(ARCHFLAGS) -Wall -fPIC -g
-CXXFLAGS = $(CFLAGS) -I$(VAMP_SDK_DIR) -I$(BOOST_ROOT)
+ARCHFLAGS ?= -isysroot /Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.6 -arch i386
+CFLAGS += $(ARCHFLAGS) -Wall -fPIC -g -O3
+CXXFLAGS += $(CFLAGS) -I$(VAMP_SDK_DIR) -I$(BOOST_ROOT)
 PLUGIN_EXT = .dylib
 PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
-LDFLAGS = $(ARCHFLAGS) -dynamiclib -install_name $(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a  -exported_symbols_list vamp-plugin.list -framework Accelerate
+LDFLAGS += $(ARCHFLAGS) -dynamiclib -install_name $(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a  -exported_symbols_list vamp-plugin.list -framework Accelerate
 
 
 $(PLUGIN): $(PLUGIN_CODE_OBJECTS)
@@ -32,7 +32,7 @@
 
 nnls.o: nnls.h
 Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h
-chromamethods.o: chromamethods.h nnls.h chorddict.cpp
+chromamethods.o: chromamethods.h nnls.h 
 NNLSBase.o: NNLSBase.h chromamethods.h nnls.h
 NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h
 plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h
--- a/NNLSBase.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/NNLSBase.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -26,7 +26,7 @@
 
 #include <algorithm>
 
-const bool debug_on = false;
+static bool debug_on = false;
 
 NNLSBase::NNLSBase(float inputSampleRate) :
     Plugin(inputSampleRate),
@@ -40,7 +40,6 @@
     m_whitening(1.0),
     m_preset(0.0),
     m_useNNLS(1.0),
-	m_useHMM(1.0),
     m_localTuning(0.0),
     m_kernelValue(0),
     m_kernelFftIndex(0),
@@ -51,13 +50,14 @@
     m_rollon(0.0),
     m_boostN(0.1),
 	m_s(0.7),
+	m_harte_syntax(0),
 	sinvalues(0),
 	cosvalues(0)
 {
     if (debug_on) cerr << "--> NNLSBase" << endl;
     // make the *note* dictionary matrix
     m_dict = new float[nNote * 84];
-    for (unsigned i = 0; i < nNote * 84; ++i) m_dict[i] = 0.0;    
+    for (int i = 0; i < nNote * 84; ++i) m_dict[i] = 0.0;    
 }
 
 
@@ -81,7 +81,7 @@
     if (debug_on) cerr << "--> getPluginVersion" << endl;
     // Increment this each time you release a version that behaves
     // differently from the previous one
-    return 3;
+    return 5;
 }
 
 string
@@ -152,8 +152,8 @@
 
     ParameterDescriptor d0;
     d0.identifier = "rollon";
-    d0.name = "spectral roll-on";
-    d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed.";
+    d0.name = "bass noise threshold";
+    d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed.";
     d0.unit = "%";
     d0.minValue = 0;
     d0.maxValue = 5;
@@ -256,10 +256,10 @@
         return m_doNormalizeChroma;
     }
     
-    if (identifier == "useHMM") {
-        return m_useHMM;
-    }
-    
+	if (identifier == "usehartesyntax") {
+		return m_harte_syntax;
+	}
+
     return 0;
     
 }
@@ -267,6 +267,8 @@
 void
 NNLSBase::setParameter(string identifier, float value) 
 {
+//    cerr << "setParameter (" << identifier << ") -> " << value << endl;
+    
     if (debug_on) cerr << "--> setParameter" << endl;
     if (identifier == "useNNLS") {
         m_useNNLS = (int) value;
@@ -280,10 +282,6 @@
         m_s = value;
     }
 
-    if (identifier == "useHMM") {
-        m_useHMM = value;
-    }
-    
     if (identifier == "boostn") {
         m_boostN = value;
     }
@@ -318,6 +316,10 @@
     if (identifier == "rollon") {
         m_rollon = value;
     }
+
+	if (identifier == "usehartesyntax") {
+		m_harte_syntax = value;
+	}
 }
 
 NNLSBase::ProgramList
@@ -395,7 +397,7 @@
     m_kernelNoteIndex.clear();
     int countNonzero = 0;
     for (int iNote = 0; iNote < nNote; ++iNote) { // I don't know if this is wise: manually making a sparse matrix
-        for (int iFFT = 0; iFFT < blockSize/2; ++iFFT) {
+        for (int iFFT = 0; iFFT < static_cast<int>(blockSize/2); ++iFFT) {
             if (tempkernel[iFFT + blockSize/2 * iNote] > 0) {
                 m_kernelValue.push_back(tempkernel[iFFT + blockSize/2 * iNote]);
                 if (tempkernel[iFFT + blockSize/2 * iNote] > 0) {
@@ -446,7 +448,7 @@
     float energysum = 0;
     // make magnitude
     float maxmag = -10000;
-    for (size_t iBin = 0; iBin < m_blockSize/2; iBin++) {
+    for (int iBin = 0; iBin < static_cast<int>(m_blockSize/2); iBin++) {
         magnitude[iBin] = sqrt(fbuf[2 * iBin] * fbuf[2 * iBin] + 
                                fbuf[2 * iBin + 1] * fbuf[2 * iBin + 1]);
         if (magnitude[iBin]>m_blockSize*1.0) magnitude[iBin] = m_blockSize; // a valid audio signal (between -1 and 1) should not be limited here.
@@ -458,16 +460,16 @@
 	
     float cumenergy = 0;
     if (m_rollon > 0) {
-        for (size_t iBin = 2; iBin < m_blockSize/2; iBin++) {
+        for (int iBin = 2; iBin < static_cast<int>(m_blockSize/2); iBin++) {
             cumenergy +=  pow(magnitude[iBin],2);
             if (cumenergy < energysum * m_rollon / 100) magnitude[iBin-2] = 0;
             else break;
         }
     }
 	
-    if (maxmag < 2) {
+    if (maxmag < m_blockSize * 2.0 / 16384.0) { // this is not quite right, I think
         // cerr << "timestamp " << timestamp << ": very low magnitude, setting magnitude to all zeros" << endl;
-        for (size_t iBin = 0; iBin < m_blockSize/2; iBin++) {
+        for (int iBin = 0; iBin < static_cast<int>(m_blockSize/2); iBin++) {
             magnitude[iBin] = 0;
         }
     }
--- a/NNLSBase.h	Mon Nov 02 12:23:00 2015 +0000
+++ b/NNLSBase.h	Mon Nov 02 12:35:13 2015 +0000
@@ -65,7 +65,6 @@
     float m_whitening;
     float m_preset;
 	float m_useNNLS;
-    float m_useHMM;
     vector<float> m_localTuning;
     vector<float> m_kernelValue;
     vector<int> m_kernelFftIndex;
@@ -76,6 +75,7 @@
     float m_rollon;
     float m_boostN;
     float m_s;
+	float m_harte_syntax;
     vector<float> hw;
     vector<float> sinvalues;
     vector<float> cosvalues;
--- a/NNLSChroma.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/NNLSChroma.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -67,6 +67,12 @@
     OutputList list;
     
     // Make chroma names for the binNames property
+
+	const char* notenames[24] = {
+	    "A  (bass)","Bb (bass)","B  (bass)","C  (bass)","C# (bass)","D  (bass)","Eb (bass)","E  (bass)","F  (bass)","F# (bass)","G  (bass)","Ab (bass)",
+	    "A","Bb","B","C","C#","D","Eb","E","F","F#","G","Ab"};
+
+	
     vector<string> chromanames;
     vector<string> bothchromanames;
     for (int iNote = 0; iNote < 24; iNote++) {
@@ -78,114 +84,101 @@
     
     int index = 0;
 
-    OutputDescriptor d1;
-    d1.identifier = "logfreqspec";
-    d1.name = "Log-Frequency Spectrum";
-    d1.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping.";
-    d1.unit = "";
-    d1.hasFixedBinCount = true;
-    d1.binCount = nNote;
-    d1.hasKnownExtents = false;
-    d1.isQuantized = false;
-    d1.sampleType = OutputDescriptor::FixedSampleRate;
-    d1.hasDuration = false;
-    d1.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d1);
-    m_outputLogSpec = index++;
+    float featureRate =
+        (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
 
-    OutputDescriptor d2;
-    d2.identifier = "tunedlogfreqspec";
-    d2.name = "Tuned Log-Frequency Spectrum";
-    d2.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping, then its tuned using the estimated tuning frequency.";
-    d2.unit = "";
-    d2.hasFixedBinCount = true;
-    d2.binCount = nNote;
-    d2.hasKnownExtents = false;
-    d2.isQuantized = false;
-    d2.sampleType = OutputDescriptor::FixedSampleRate;
-    d2.hasDuration = false;
-    d2.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d2);
-    m_outputTunedSpec = index++;
+    OutputDescriptor logfreqspecOutput;
+    logfreqspecOutput.identifier = "logfreqspec";
+    logfreqspecOutput.name = "Log-Frequency Spectrum";
+    logfreqspecOutput.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping.";
+    logfreqspecOutput.unit = "";
+    logfreqspecOutput.hasFixedBinCount = true;
+    logfreqspecOutput.binCount = nNote;
+    logfreqspecOutput.hasKnownExtents = false;
+    logfreqspecOutput.isQuantized = false;
+    logfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    logfreqspecOutput.hasDuration = false;
+    logfreqspecOutput.sampleRate = featureRate;
+    list.push_back(logfreqspecOutput);
+    m_outputLogfreqspec = index++;
+
+    OutputDescriptor tunedlogfreqspecOutput;
+    tunedlogfreqspecOutput.identifier = "tunedlogfreqspec";
+    tunedlogfreqspecOutput.name = "Tuned Log-Frequency Spectrum";
+    tunedlogfreqspecOutput.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping, then its tuned using the estimated tuning frequency.";
+    tunedlogfreqspecOutput.unit = "";
+    tunedlogfreqspecOutput.hasFixedBinCount = true;
+    tunedlogfreqspecOutput.binCount = nNote;
+    tunedlogfreqspecOutput.hasKnownExtents = false;
+    tunedlogfreqspecOutput.isQuantized = false;
+    tunedlogfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    tunedlogfreqspecOutput.hasDuration = false;
+    tunedlogfreqspecOutput.sampleRate = featureRate;
+    list.push_back(tunedlogfreqspecOutput);
+    m_outputTunedlogfreqspec = index++;
     
-    OutputDescriptor d3;
-    d3.identifier = "semitonespectrum";
-    d3.name = "Semitone Spectrum";
-    d3.description = "A semitone-spaced log-frequency spectrum derived from the third-of-a-semitone-spaced tuned log-frequency spectrum.";
-    d3.unit = "";
-    d3.hasFixedBinCount = true;
-    d3.binCount = 84;
-    d3.hasKnownExtents = false;
-    d3.isQuantized = false;
-    d3.sampleType = OutputDescriptor::FixedSampleRate;
-    d3.hasDuration = false;
-    d3.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d3);
-    m_outputSemiSpec = index++;
+    OutputDescriptor semitonespectrumOutput;
+    semitonespectrumOutput.identifier = "semitonespectrum";
+    semitonespectrumOutput.name = "Semitone Spectrum";
+    semitonespectrumOutput.description = "A semitone-spaced log-frequency spectrum derived from the third-of-a-semitone-spaced tuned log-frequency spectrum.";
+    semitonespectrumOutput.unit = "";
+    semitonespectrumOutput.hasFixedBinCount = true;
+    semitonespectrumOutput.binCount = 84;
+    semitonespectrumOutput.hasKnownExtents = false;
+    semitonespectrumOutput.isQuantized = false;
+    semitonespectrumOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    semitonespectrumOutput.hasDuration = false;
+    semitonespectrumOutput.sampleRate = featureRate;
+    list.push_back(semitonespectrumOutput);
+    m_outputSemitonespectrum = index++;
     
-    OutputDescriptor d4;
-    d4.identifier = "chroma";
-    d4.name = "Chromagram";
-    d4.description = "Tuning-adjusted chromagram from NNLS approximate transcription, with an emphasis on the medium note range.";
-    d4.unit = "";
-    d4.hasFixedBinCount = true;
-    d4.binCount = 12;
-    d4.binNames = chromanames;
-    d4.hasKnownExtents = false;
-    d4.isQuantized = false;
-    d4.sampleType = OutputDescriptor::FixedSampleRate;
-    d4.hasDuration = false;
-    d4.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d4);
+    OutputDescriptor chromaOutput;
+    chromaOutput.identifier = "chroma";
+    chromaOutput.name = "Chromagram";
+    chromaOutput.description = "Tuning-adjusted chromagram from NNLS approximate transcription, with an emphasis on the medium note range.";
+    chromaOutput.unit = "";
+    chromaOutput.hasFixedBinCount = true;
+    chromaOutput.binCount = 12;
+    chromaOutput.binNames = chromanames;
+    chromaOutput.hasKnownExtents = false;
+    chromaOutput.isQuantized = false;
+    chromaOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    chromaOutput.hasDuration = false;
+    chromaOutput.sampleRate = featureRate;
+    list.push_back(chromaOutput);
     m_outputChroma = index++;
     
-    OutputDescriptor d5;
-    d5.identifier = "basschroma";
-    d5.name = "Bass Chromagram";
-    d5.description = "Tuning-adjusted bass chromagram from NNLS approximate transcription, with an emphasis on the bass note range.";
-    d5.unit = "";
-    d5.hasFixedBinCount = true;
-    d5.binCount = 12;
-    d5.binNames = chromanames;
-    d5.hasKnownExtents = false;
-    d5.isQuantized = false;
-    d5.sampleType = OutputDescriptor::FixedSampleRate;
-    d5.hasDuration = false;
-    d5.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d5);
-    m_outputBassChroma = index++;
+    OutputDescriptor basschromaOutput;
+    basschromaOutput.identifier = "basschroma";
+    basschromaOutput.name = "Bass Chromagram";
+    basschromaOutput.description = "Tuning-adjusted bass chromagram from NNLS approximate transcription, with an emphasis on the bass note range.";
+    basschromaOutput.unit = "";
+    basschromaOutput.hasFixedBinCount = true;
+    basschromaOutput.binCount = 12;
+    basschromaOutput.binNames = chromanames;
+    basschromaOutput.hasKnownExtents = false;
+    basschromaOutput.isQuantized = false;
+    basschromaOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    basschromaOutput.hasDuration = false;
+    basschromaOutput.sampleRate = featureRate;
+    list.push_back(basschromaOutput);
+    m_outputBasschroma = index++;
     
-    OutputDescriptor d6;
-    d6.identifier = "bothchroma";
-    d6.name = "Chromagram and Bass Chromagram";
-    d6.description = "Tuning-adjusted chromagram and bass chromagram (stacked on top of each other) from NNLS approximate transcription.";
-    d6.unit = "";
-    d6.hasFixedBinCount = true;
-    d6.binCount = 24;
-    d6.binNames = bothchromanames;
-    d6.hasKnownExtents = false;
-    d6.isQuantized = false;
-    d6.sampleType = OutputDescriptor::FixedSampleRate;
-    d6.hasDuration = false;
-    d6.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d6);
-    m_outputBothChroma = index++;
-  
-    OutputDescriptor d7;
-    d7.identifier = "consonance";
-    d7.name = "Consonance estimate.";
-    d7.description = "A simple consonance value based on the convolution of a consonance profile with the semitone spectrum.";
-    d7.unit = "";
-    d7.hasFixedBinCount = true;
-    d7.binCount = 1;
-    d7.hasKnownExtents = false;
-    d7.isQuantized = false;
-    d7.sampleType = OutputDescriptor::FixedSampleRate;
-    d7.hasDuration = false;
-    d7.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
-    list.push_back(d7);
-    m_outputConsonance = index++;
-  
+    OutputDescriptor bothchromaOutput;
+    bothchromaOutput.identifier = "bothchroma";
+    bothchromaOutput.name = "Chromagram and Bass Chromagram";
+    bothchromaOutput.description = "Tuning-adjusted chromagram and bass chromagram (stacked on top of each other) from NNLS approximate transcription.";
+    bothchromaOutput.unit = "";
+    bothchromaOutput.hasFixedBinCount = true;
+    bothchromaOutput.binCount = 24;
+    bothchromaOutput.binNames = bothchromanames;
+    bothchromaOutput.hasKnownExtents = false;
+    bothchromaOutput.isQuantized = false;
+    bothchromaOutput.sampleType = OutputDescriptor::FixedSampleRate;
+    bothchromaOutput.hasDuration = false;
+    bothchromaOutput.sampleRate = featureRate;
+    list.push_back(bothchromaOutput);
+    m_outputBothchroma = index++;    
     return list;
 }
 
@@ -219,29 +212,18 @@
     NNLSBase::baseProcess(inputBuffers, timestamp);
 	
     FeatureSet fs;
-    fs[m_outputLogSpec].push_back(m_logSpectrum[m_logSpectrum.size()-1]);
+    fs[m_outputLogfreqspec].push_back(m_logSpectrum[m_logSpectrum.size()-1]);
     return fs;	
 }
 
 NNLSChroma::FeatureSet
 NNLSChroma::getRemainingFeatures()
 {
-    static const int nConsonance = 24;
-    float consonancepattern[nConsonance] = {0,-1,-1,1,1,1,-1,1,1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,-1,-1};
-    float consonancemean = 0;
-    for (int i = 0; i< nConsonance; ++i) {
-        consonancemean += consonancepattern[i]/nConsonance;
-    }
     
-    cerr << "consonancemean = " << consonancemean << endl;
-    
-    for (int i = 0; i< nConsonance; ++i) {
-        consonancepattern[i] -= consonancemean;
-    }
-    if (debug_on) cerr << "--> getRemainingFeatures" << endl;
+	if (debug_on) cerr << "--> getRemainingFeatures" << endl;
     FeatureSet fsOut;
     if (m_logSpectrum.size() == 0) return fsOut;
-    // 
+
     /**  Calculate Tuning
          calculate tuning from (using the angle of the complex number defined by the 
          cumulative mean real and imag values)
@@ -260,19 +242,15 @@
     char buffer0 [50];
 		
     sprintf(buffer0, "estimated tuning: %0.1f Hz", cumulativetuning);
-		    
-    // cerr << "normalisedtuning: " << normalisedtuning << '\n';
-		    
+		    		    
     /** Tune Log-Frequency Spectrogram
         calculate a tuned log-frequency spectrogram (f2): use the tuning estimated above (kinda f0) to 
         perform linear interpolation on the existing log-frequency spectrogram (kinda f1).
     **/
-    cerr << endl << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... ";
+    if (debug_on) cerr << endl << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... ";
 					
     float tempValue = 0;
-    float dbThreshold = 0; // relative to the background spectrum
-    float thresh = pow(10,dbThreshold/20);
-    // cerr << "tune local ? " << m_tuneLocal << endl;
+
     int count = 0;
 
 		
@@ -291,7 +269,7 @@
 		        
         // cerr << intShift << " " << floatShift << endl;
 		        
-        for (unsigned k = 2; k < f1.values.size() - 3; ++k) { // interpolate all inner bins
+        for (int k = 2; k < (int)f1.values.size() - 3; ++k) { // interpolate all inner bins
             tempValue = f1.values[k + intShift] * (1-floatShift) + f1.values[k+intShift+1] * floatShift;
             f2.values.push_back(tempValue);
         }
@@ -316,10 +294,10 @@
                 cerr << "ERROR: negative value in logfreq spectrum" << endl;
             }
         }
-        fsOut[m_outputTunedSpec].push_back(f2);
+        fsOut[m_outputTunedlogfreqspec].push_back(f2);
         count++;
     }
-    cerr << "done." << endl;
+    if (debug_on) cerr << "done." << endl;
 	    
     /** Semitone spectrum and chromagrams
         Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum
@@ -328,9 +306,9 @@
         bass and treble stacked onto each other).
     **/
     if (m_useNNLS == 0) {
-        cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... ";
+        if (debug_on) cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... ";
     } else {
-        cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... ";
+        if (debug_on) cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... ";
     }
 
 	    
@@ -338,13 +316,12 @@
     vector<float> oldbasschroma = vector<float>(12,0);
     count = 0;
 
-    for (FeatureList::iterator it = fsOut[m_outputTunedSpec].begin(); it != fsOut[m_outputTunedSpec].end(); ++it) {
+    for (FeatureList::iterator it = fsOut[m_outputTunedlogfreqspec].begin(); it != fsOut[m_outputTunedlogfreqspec].end(); ++it) {
         Feature f2 = *it; // logfreq spectrum
         Feature f3; // semitone spectrum
         Feature f4; // treble chromagram
         Feature f5; // bass chromagram
         Feature f6; // treble and bass chromagram
-	    Feature consonance;
 	    
         f3.hasTimestamp = true;
         f3.timestamp = f2.timestamp;
@@ -358,9 +335,6 @@
         f6.hasTimestamp = true;
         f6.timestamp = f2.timestamp;
 	        
-        consonance.hasTimestamp = true;
-        consonance.timestamp = f2.timestamp;
-	    
         float b[nNote];
 	
         bool some_b_greater_zero = false;
@@ -379,11 +353,11 @@
         vector<float> chroma = vector<float>(12, 0);
         vector<float> basschroma = vector<float>(12, 0);
         float currval;
-        unsigned iSemitone = 0;
+        int iSemitone = 0;
 			
         if (some_b_greater_zero) {
             if (m_useNNLS == 0) {
-                for (unsigned iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) {
+                for (int iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) {
                     currval = 0;
                     for (int iBPS = -nBPS/2; iBPS < nBPS/2+1; ++iBPS) {
                         currval += b[iNote + iBPS] * (1-abs(iBPS*1.0/(nBPS/2+1)));						
@@ -400,7 +374,7 @@
                 vector<int> signifIndex;
                 int index=0;
                 sumb /= 84.0;
-                for (unsigned iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) {
+                for (int iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) {
                     float currval = 0;
                     for (int iBPS = -nBPS/2; iBPS < nBPS/2+1; ++iBPS) {
                         currval += b[iNote + iBPS]; 
@@ -435,19 +409,7 @@
             for (int i = 0; i < 84; ++i) f3.values.push_back(0);
         }
 		
-        float notesum = 0;
-        
-        consonance.values.push_back(0);
-        for (int iSemitone = 0; iSemitone < 84-24; ++iSemitone) {            
-            notesum += f3.values[iSemitone] * f3.values[iSemitone] * treblewindow[iSemitone] * treblewindow[iSemitone];
-            float tempconsonance = 0;
-            for (int jSemitone = 1; jSemitone < 24; ++jSemitone) {
-                tempconsonance += f3.values[iSemitone+jSemitone] * (consonancepattern[jSemitone]) * treblewindow[iSemitone+jSemitone];
-            }
-            consonance.values[0] += (f3.values[iSemitone] * tempconsonance * treblewindow[iSemitone]);
-        }
-        if (notesum > 0) consonance.values[0] /= notesum;
-		
+
         f4.values = chroma; 
         f5.values = basschroma;
         chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas 
@@ -490,30 +452,29 @@
                 break;
             }
             if (chromanorm[0] > 0) {
-                for (size_t i = 0; i < f4.values.size(); i++) {
+                for (int i = 0; i < (int)f4.values.size(); i++) {
                     f4.values[i] /= chromanorm[0];
                 }
             }
             if (chromanorm[1] > 0) {
-                for (size_t i = 0; i < f5.values.size(); i++) {
+                for (int i = 0; i < (int)f5.values.size(); i++) {
                     f5.values[i] /= chromanorm[1];
                 }
             }
             if (chromanorm[2] > 0) {
-                for (size_t i = 0; i < f6.values.size(); i++) {
+                for (int i = 0; i < (int)f6.values.size(); i++) {
                     f6.values[i] /= chromanorm[2];
                 }
             }
         }
 	
-        fsOut[m_outputSemiSpec].push_back(f3);
+        fsOut[m_outputSemitonespectrum].push_back(f3);
         fsOut[m_outputChroma].push_back(f4);
-        fsOut[m_outputBassChroma].push_back(f5);
-        fsOut[m_outputBothChroma].push_back(f6);
-        fsOut[m_outputConsonance].push_back(consonance);
+        fsOut[m_outputBasschroma].push_back(f5);
+        fsOut[m_outputBothchroma].push_back(f6);
         count++;
     }
-    cerr << "done." << endl;
+    if (debug_on) cerr << "done." << endl;
 
     return fsOut;     
 
--- a/NNLSChroma.h	Mon Nov 02 12:23:00 2015 +0000
+++ b/NNLSChroma.h	Mon Nov 02 12:35:13 2015 +0000
@@ -44,13 +44,12 @@
     void reset();
 
 protected:
-    mutable int m_outputLogSpec;
-    mutable int m_outputTunedSpec;
-    mutable int m_outputSemiSpec;
+    mutable int m_outputLogfreqspec;
+    mutable int m_outputTunedlogfreqspec;
+    mutable int m_outputSemitonespectrum;
     mutable int m_outputChroma;
-    mutable int m_outputBassChroma;
-    mutable int m_outputBothChroma;
-    mutable int m_outputConsonance;
+    mutable int m_outputBasschroma;
+    mutable int m_outputBothchroma;
 };
 
 
--- a/README	Mon Nov 02 12:23:00 2015 +0000
+++ b/README	Mon Nov 02 12:35:13 2015 +0000
@@ -78,5 +78,25 @@
 
 ### References and Credits ###
 
+If you make use of this software for any public or commercial purpose,
+we ask you to kindly mention the authors and Queen Mary, University of
+London in your user-visible documentation. We're very happy to see
+this sort of use, but would much appreciate being credited, separately
+from the requirements of the software license itself (see below).
+
+If you make use of this software for academic purposes, please cite:
+
 Mauch, Matthias and Dixon, Simon: [*Approximate Note Transcription for the Improved Identification of Difficult Chords*](http://schall-und-mauch.de/artificialmusicality/?p=89), Proceedings of the 11th International Society for Music Information Retrieval Conference (ISMIR 2010), 2010.
 
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or (at
+your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
--- a/Tuning.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/Tuning.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -76,8 +76,8 @@
 
     ParameterDescriptor d0;
     d0.identifier = "rollon";
-    d0.name = "spectral roll-on";
-    d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed.";
+    d0.name = "bass noise threshold";
+    d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed.";
     d0.unit = "%";
     d0.minValue = 0;
     d0.maxValue = 5;
@@ -126,8 +126,8 @@
     d10.maxValue = 452.89;
     d10.isQuantized = false;
     d10.sampleType = OutputDescriptor::FixedSampleRate;
+    d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
     d10.hasDuration = false;
-    // d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
     list.push_back(d10);
     m_outputLocalTuning = index++;
   
--- a/chord.dict	Mon Nov 02 12:23:00 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-### Comma-Separated Chord Dictionaries
-# 
-# field 1 is chord type name,
-# fields 2-25 indicate whether a pitch class is present (1) or not (0) :
-#   - fields 2-13 correspond to bass pitch classes A through Ab
-#   - fields 14-25 correspond to chord pitch classes A through Ab
-
-### Advanced Learners Chord Dictionary
-=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-m=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
-m=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
-dim7=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
-dim7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
-6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
-7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
-maj7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
-m7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0
-m6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
-=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-dim=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
-aug=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
-=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 
-7=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
-# sus4=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0
-
-### Rock'n'Roll
-# :1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-# m:1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chord.dictold	Mon Nov 02 12:35:13 2015 +0000
@@ -0,0 +1,31 @@
+### Comma-Separated Chord Dictionaries
+# 
+# field 1 is chord type name,
+# fields 2-25 indicate whether a pitch class is present (1) or not (0) :
+#   - fields 2-13 correspond to bass pitch classes A through Ab
+#   - fields 14-25 correspond to chord pitch classes A through Ab
+
+### Advanced Learners Chord Dictionary
+=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+m=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
+m=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
+dim7=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
+dim7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
+6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
+7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
+maj7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
+m7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0
+m6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
+=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+dim=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
+aug=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
+=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 
+7=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
+# sus4=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0
+
+### Rock'n'Roll
+# :1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+# m:1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
--- a/chorddict.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-
-// #include <string>
-const int nChorddict = 2904;
-const char* chordtypes[] = {"", "", "", "", "", "", "", "", "", "", "", "", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ""};
-
-const float chorddict[] = 
- {0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.417029, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.417029, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 
-0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 
-0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 
-0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 
-0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.471405, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 
-0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 
-0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 
-0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 
-0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 
-0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 
-0.471405, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 
-0.129099, 0.129099, 0.129099, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, 
-0.258199, 0.258199, 0.258199, 0.258199, 0.258199};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chordextract.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -0,0 +1,149 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+  NNLS-Chroma / Chordino
+
+  Audio feature extraction plugins for chromagram and chord
+  estimation.
+
+  Centre for Digital Music, Queen Mary University of London.
+  This file copyright 2014 QMUL.
+    
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.  See the file
+  COPYING included with this distribution for more information.
+*/
+
+/*
+  Extract chords from an audio file, read using libsndfile.  Works by
+  constructing the plugin as a C++ class directly, and using plugin
+  adapters from the Vamp Host SDK to provide input.
+
+  You can compile this with e.g. the following (Linux example):
+
+  $ g++ -D_VAMP_PLUGIN_IN_HOST_NAMESPACE -O2 -ffast-math chordextract.cpp Chordino.cpp NNLSBase.cpp chromamethods.cpp viterbi.cpp nnls.c -o chordextract -lsndfile -lvamp-hostsdk -ldl
+
+  But the same idea should work on any platform, so long as the Boost
+  Tokenizer headers and the Vamp Host SDK library are available and
+  the _VAMP_PLUGIN_IN_HOST_NAMESPACE preprocessor symbol is defined
+  throughout.
+*/
+
+#define _VAMP_PLUGIN_IN_HOST_NAMESPACE 1
+
+#include <vamp-hostsdk/PluginInputDomainAdapter.h>
+#include <vamp-hostsdk/PluginBufferingAdapter.h>
+
+#include "Chordino.h"
+
+#include <sndfile.h>
+
+#include <iostream>
+#include <string>
+
+using namespace std;
+using namespace Vamp;
+using namespace Vamp::HostExt;
+
+int main(int argc, char **argv)
+{
+    const char *myname = argv[0];
+
+    if (argc != 2) {
+	cerr << "usage: " << myname << " file.wav" << endl;
+	return 2;
+    }
+
+    const char *infile = argv[1];
+
+    SF_INFO sfinfo;
+    SNDFILE *sndfile = sf_open(infile, SFM_READ, &sfinfo);
+
+    if (!sndfile) {
+	cerr << myname << ": Failed to open input file " << infile
+	     << ": " << sf_strerror(sndfile) << endl;
+	return 1;
+    }
+
+    Chordino *chordino = new Chordino(sfinfo.samplerate);
+    PluginInputDomainAdapter *ia = new PluginInputDomainAdapter(chordino);
+    ia->setProcessTimestampMethod(PluginInputDomainAdapter::ShiftData);
+    PluginBufferingAdapter *adapter = new PluginBufferingAdapter(ia);
+
+    int blocksize = adapter->getPreferredBlockSize();
+
+    // Plugin requires 1 channel (we will mix down)
+    if (!adapter->initialise(1, blocksize, blocksize)) {
+	cerr << myname << ": Failed to initialise Chordino adapter!" << endl;
+	return 1;
+    }
+
+    float *filebuf = new float[sfinfo.channels * blocksize];
+    float *mixbuf = new float[blocksize];
+
+    Plugin::FeatureList chordFeatures;
+    Plugin::FeatureSet fs;
+
+    int chordFeatureNo = -1;
+    Plugin::OutputList outputs = adapter->getOutputDescriptors();
+    for (int i = 0; i < int(outputs.size()); ++i) {
+	if (outputs[i].identifier == "simplechord") {
+	    chordFeatureNo = i;
+	}
+    }
+    if (chordFeatureNo < 0) {
+	cerr << myname << ": Failed to identify chords output!" << endl;
+	return 1;
+    }
+    
+    int frame = 0;
+    while (frame < sfinfo.frames) {
+
+	int count = -1;
+	if ((count = sf_readf_float(sndfile, filebuf, blocksize)) <= 0) break;
+
+	// mix down
+	for (int i = 0; i < blocksize; ++i) {
+	    mixbuf[i] = 0.f;
+	    if (i < count) {
+		for (int c = 0; c < sfinfo.channels; ++c) {
+		    mixbuf[i] += filebuf[i * sfinfo.channels + c] / sfinfo.channels;
+		}
+	    }
+	}
+
+	RealTime timestamp = RealTime::frame2RealTime(frame, sfinfo.samplerate);
+	
+	// feed to plugin: can just take address of buffer, as only one channel
+	fs = adapter->process(&mixbuf, timestamp);
+
+	chordFeatures.insert(chordFeatures.end(),
+			     fs[chordFeatureNo].begin(),
+			     fs[chordFeatureNo].end());
+
+	frame += count;
+    }
+
+    sf_close(sndfile);
+
+    // features at end of processing (actually Chordino does all its work here)
+    fs = adapter->getRemainingFeatures();
+
+    // chord output is output index 0
+    chordFeatures.insert(chordFeatures.end(),
+			 fs[chordFeatureNo].begin(),
+			 fs[chordFeatureNo].end());
+
+    for (int i = 0; i < (int)chordFeatures.size(); ++i) {
+	cout << chordFeatures[i].timestamp.toString() << ": "
+	     << chordFeatures[i].label << endl;
+    }
+
+    delete[] filebuf;
+    delete[] mixbuf;
+    
+    delete adapter;
+}
+
--- a/chromamethods.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/chromamethods.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -31,16 +31,16 @@
 #include <boost/iostreams/stream.hpp>
 #include <boost/lexical_cast.hpp>
 
-#include "chorddict.cpp"
-
 using namespace std;
 using namespace boost;
 
 
 /** Special Convolution
-    special convolution is as long as the convolvee, i.e. the first argument. in the valid core part of the 
-    convolution it contains the usual convolution values, but the pads at the beginning (ending) have the same values
-    as the first (last) valid convolution bin.
+    Special convolution is as long as the convolvee, i.e. the first argument. 
+	In the "valid" core part of the convolution it contains the usual convolution 
+	values, but the parts at the beginning (ending) that would normally be 
+	calculated using zero padding simply have the same values as the first 
+	(last) valid convolution bin.
 **/
 
 vector<float> SpecialConvolution(vector<float> convolvee, vector<float> kernel)
@@ -71,15 +71,6 @@
     return Z;
 }
 
-// vector<float> FftBin2Frequency(vector<float> binnumbers, int fs, int blocksize)
-// {
-// 	vector<float> freq(binnumbers.size, 0.0);
-// 	for (unsigned i = 0; i < binnumbers.size; ++i) {
-// 		freq[i] = (binnumbers[i]-1.0) * fs * 1.0 / blocksize;	
-// 	}
-// 	return freq;
-// }
-
 float cospuls(float x, float centre, float width) 
 {
     float recipwidth = 1.0/width;
@@ -103,7 +94,13 @@
     return out;
 }
 
+/**
+ * Calculates a matrix that can be used to linearly map from the magnitude spectrum to a pitch-scale spectrum.
+ * @return this always returns true, which is a bit stupid, really. The main purpose of the function is to change the values in the "matrix" pointed to by *outmatrix
+ */
 bool logFreqMatrix(int fs, int blocksize, float *outmatrix) {
+	// TODO: rewrite so that everyone understands what is done here.
+	// TODO: make this more general, such that it works with all minoctave, maxoctave and whatever nBPS (or check if it already does)
 	
     int binspersemitone = nBPS; 
     int minoctave = 0; // this must be 0
@@ -128,8 +125,6 @@
     int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone!
     vector<float> cq_f;
     float oob = 1.0/binspersemitone; // one over binspersemitone
-    // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-69))); // 0.083333 is approx 1/12
-    // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI+oob-69)));
     for (int i = minMIDI; i < maxMIDI; ++i) {
         for (int k = 0; k < binspersemitone; ++k)	 {
             cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69)));
@@ -146,6 +141,10 @@
         fft_activation.push_back(cosp);
         // cerr << cosp << endl;
     }
+
+    for (int i = 0; i < nFFT * (int)cq_f.size(); ++i) {
+        outmatrix[i] = 0.f;
+    }
 	
     float cq_activation;
     for (int iFFT = 1; iFFT < nFFT; ++iFFT) {
@@ -153,52 +152,45 @@
         int curr_start = oversampling * iFFT - oversampling;
         int curr_end = oversampling * iFFT + oversampling; // don't know if I should add "+1" here
         // cerr << oversampled_f[curr_start] << " " << fft_f[iFFT] << " " << oversampled_f[curr_end] << endl;
-        for (unsigned iCQ = 0; iCQ < cq_f.size(); ++iCQ) {
-            outmatrix[iFFT + nFFT * iCQ] = 0;
+        for (int iCQ = 0; iCQ < (int)cq_f.size(); ++iCQ) {
             if (cq_f[iCQ] * pow(2.0, 0.084) + fft_width > fft_f[iFFT] && cq_f[iCQ] * pow(2.0, -0.084 * 2) - fft_width < fft_f[iFFT]) { // within a generous neighbourhood
                 for (int iOS = curr_start; iOS < curr_end; ++iOS) {
                     cq_activation = pitchCospuls(oversampled_f[iOS],cq_f[iCQ],binspersemitone*12);
                     // cerr << oversampled_f[iOS] << " " << cq_f[iCQ] << " " << cq_activation << endl;
                     outmatrix[iFFT + nFFT * iCQ] += cq_activation * fft_activation[iOS-curr_start];
                 }				
-                // if (iCQ == 1 || iCQ == 2) {
-                // 	cerr << " " << outmatrix[iFFT + nFFT * iCQ] << endl;
-                // }
-            }
+             }
         }
     }
     return true;	
 }
 
 void dictionaryMatrix(float* dm, float s_param) {
+	// TODO: make this more general, such that it works with all minoctave, maxoctave and even more than one note per semitone
     int binspersemitone = nBPS;
     int minoctave = 0; // this must be 0
     int maxoctave = 7; // this must be 7
-    // float s_param = 0.7;
 	
     // pitch-spaced frequency vector
     int minMIDI = 21 + minoctave * 12 - 1; // this includes one additional semitone!
     int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone!
     vector<float> cq_f;
     float oob = 1.0/binspersemitone; // one over binspersemitone
-    // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-69))); // 0.083333 is approx 1/12
-    // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI+oob-69)));
     for (int i = minMIDI; i < maxMIDI; ++i) {
         for (int k = 0; k < binspersemitone; ++k)	 {
             cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69)));
         }
     }
-    // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-oob-69)));
     cq_f.push_back(440 * pow(2.0,0.083333 * (maxMIDI-69)));
 
-    float curr_f;
+//    float curr_f;
     float floatbin;
     float curr_amp;
     // now for every combination calculate the matrix element
     for (int iOut = 0; iOut < 12 * (maxoctave - minoctave); ++iOut) {
         // cerr << iOut << endl;
         for (int iHarm = 1; iHarm <= 20; ++iHarm) {
-            curr_f = 440 * pow(2,(minMIDI-69+iOut)*1.0/12) * iHarm;
+//            curr_f = 440 * pow(2,(minMIDI-69+iOut)*1.0/12) * iHarm;
             // if (curr_f > cq_f[nNote-1])  break;
             floatbin = ((iOut + 1) * binspersemitone + 1) + binspersemitone * 12 * log2(iHarm);
             // cerr << floatbin << endl;
@@ -212,8 +204,6 @@
             }
         }
     }
-
-
 }
 
 static
@@ -285,8 +275,8 @@
     chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
     chordnames.push_back("m");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
     chordnames.push_back("m");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
-    chordnames.push_back("dim7");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
-    chordnames.push_back("dim7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
+    chordnames.push_back("m7b5");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
+    chordnames.push_back("m7b5");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
     chordnames.push_back("6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
     chordnames.push_back("7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
     chordnames.push_back("maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
@@ -294,11 +284,30 @@
     chordnames.push_back("m6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
     chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
     chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
-    chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
+    chordnames.push_back("dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
     chordnames.push_back("aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
     chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
     chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 
     chordnames.push_back("7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
+	// from here: Harte syntax
+    chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+    chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+    chordnames.push_back(":min");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
+    chordnames.push_back(":min");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0
+    chordnames.push_back(":hdim7");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0
+    chordnames.push_back(":hdim7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0
+    chordnames.push_back(":maj6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0
+    chordnames.push_back(":7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
+    chordnames.push_back(":maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1
+    chordnames.push_back(":min7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0
+    chordnames.push_back(":min6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0
+    chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+    chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+    chordnames.push_back(":dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0
+    chordnames.push_back(":aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0
+    chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
+    chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 
+    chordnames.push_back(":7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0
     return chordnames;
 }
 
@@ -330,7 +339,7 @@
     return chordvalues;
 }
 
-vector<string> chordDictionary(vector<float> *mchorddict, vector<vector<int> > *m_chordnotes, float boostN) {    
+vector<string> chordDictionary(vector<float> *mchorddict, vector<vector<int> > *m_chordnotes, float boostN, float harte_syntax) {    
     
     typedef tokenizer<char_separator<char> > Tok;
     char_separator<char> sep(",; ","=");
@@ -340,22 +349,43 @@
 
     vector<string> ppath = getPluginPath();
     
+	const char* notenames[24] = {
+	    "A  (bass)","Bb (bass)","B  (bass)","C  (bass)","C# (bass)","D  (bass)","Eb (bass)","E  (bass)","F  (bass)","F# (bass)","G  (bass)","Ab (bass)",
+	    "A","Bb","B","C","C#","D","Eb","E","F","F#","G","Ab"};
+
+	const char* bassnames[13][12] ={
+	    {"A","","B","C","C#","D","","E","","F#","G","G#"},
+	    {"Bb","","C","Db","D","Eb","","F","","G","Ab","A"},
+	    {"B","","C#","D","D#","E","","F#","","G#","A","A#"},
+	    {"C","","D","Eb","E","F","","G","","A","Bb","B"},
+	    {"C#","","D#","E","E#","F#","","G#","","A#","B","B#"},
+	    {"D","","E","F","F#","G","","A","","B","C","C#"},
+	    {"Eb","","F","Gb","G","Ab","","Bb","","C","Db","D"},
+	    {"E","","F#","G","G#","A","","B","","C#","D","D#"},
+	    {"F","","G","Ab","A","Bb","","C","","D","Eb","E"},
+	    {"F#","","G#","A","A#","B","","C#","","D#","E","E#"},
+	    {"G","","A","Bb","B","C","","D","","E","F","F#"},
+	    {"Ab","","Bb","Cb","C","Db","","Eb","","F","Gb","G"},
+            {"1","","2","b3","3","4","","5","","6","b7","7"}
+	};
+
     bool hasExternalDictinoary = true;
-    
-    for (size_t i = 0; i < ppath.size(); ++i) {
+	int ppathsize = static_cast<int>(ppath.size());
+    for (int i = 0; i < ppathsize; ++i) {
     	chordDictFilename = ppath[i] + "/" + chordDictBase;
-    	cerr << "Looking for chord.dict in " << chordDictFilename << "..." ;
+//    	cerr << "Looking for chord.dict in " << chordDictFilename << "..." ;
     	fstream fin;
         fin.open(chordDictFilename.c_str(),ios::in);
         if( fin.is_open() )
         {
             fin.close();
-    	    cerr << " success." << endl;
+//    	    cerr << " success." << endl;
     	    break;
         } else {
-            if (i+1 < ppath.size()) cerr << " (not found yet) ..." << endl;
-            else {
-                cerr << "* WARNING: failed to find chord dictionary, using default chord dictionary." << endl;
+            if (i+1 < ppathsize) {
+//                cerr << " (not found yet) ..." << endl;
+            } else {
+//                cerr << "* WARNING: failed to find chord dictionary, using default chord dictionary." << endl;
                 hasExternalDictinoary = false;                
             } 
         }
@@ -366,12 +396,17 @@
     // int iElement = 0;
     int nChord = 0;
 	
+	vector<float> tempChordDict = staticChordvalues();
     vector<string> tempChordNames = staticChordnames();
-    vector<float> tempChordDict = staticChordvalues();
+	if (harte_syntax == 1.0) {
+		tempChordNames.erase(tempChordNames.begin(),tempChordNames.begin()+tempChordNames.size()/2);
+	} else {
+		tempChordNames.erase(tempChordNames.begin()+tempChordNames.size()/2,tempChordNames.begin()+tempChordNames.size());
+	}
+
     vector<string> loadedChordNames;
     vector<float> loadedChordDict;
     if (hasExternalDictinoary && chordDictFile.is_open()) {
-        cerr << "-----------------> " << tempChordNames.size() << endl;
         tempChordDict.clear();
         tempChordNames.clear();
         while (std::getline(chordDictFile, line)) { // loop over lines in chord.dict file	            	
@@ -398,6 +433,7 @@
                 tempChordNames.push_back(chordType);
             }
         }
+        cerr << "-----------------> " << tempChordNames.size() << endl;
     }
     
         
@@ -409,7 +445,11 @@
             string slashNotation = "";
             for (int kSemitone = 1; kSemitone < 12; kSemitone++) {
                 if (tempChordDict[24*iType+(kSemitone) % 12] > 0.99) {
-                    slashNotation = bassnames[iSemitone][kSemitone];
+					if (harte_syntax == 0.0) {
+						slashNotation = bassnames[iSemitone][kSemitone];
+					} else {
+					        slashNotation = bassnames[12][kSemitone]; 
+                                        }
                 }
             }
             if (slashNotation=="") tempchordnotes.push_back(MIDI_basenote + (iSemitone+12) % 12);
@@ -448,8 +488,8 @@
 
     // N type
     loadedChordNames.push_back("N");
-    for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(0.5);
-    for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(1.0);
+    for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(0.5);
+    for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(1.0);
     vector<int> tempchordvector;
     m_chordnotes->push_back(tempchordvector);
     float exponent = 2.0;
--- a/chromamethods.h	Mon Nov 02 12:23:00 2015 +0000
+++ b/chromamethods.h	Mon Nov 02 12:35:13 2015 +0000
@@ -29,28 +29,9 @@
 
 extern std::vector<float> SpecialConvolution(std::vector<float> convolvee, std::vector<float> kernel);
 extern void dictionaryMatrix(float* dm, float s_param);
-extern std::vector<std::string> chordDictionary(std::vector<float> *mchorddict, std::vector<std::vector<int> > *m_chordnotes, float boostN);
+extern std::vector<std::string> chordDictionary(std::vector<float> *mchorddict, std::vector<std::vector<int> > *m_chordnotes, float boostN, float harte_syntax);
 extern bool logFreqMatrix(int fs, int blocksize, float *outmatrix);
 
-static const char* notenames[24] = {
-    "A  (bass)","Bb (bass)","B  (bass)","C  (bass)","C# (bass)","D  (bass)","Eb (bass)","E  (bass)","F  (bass)","F# (bass)","G  (bass)","Ab (bass)",
-    "A","Bb","B","C","C#","D","Eb","E","F","F#","G","Ab"};
-
-static const char* bassnames[12][12] ={
-    {"A","","B","C","C#","D","","E","","F#","G","G#"},
-    {"Bb","","C","Db","D","Eb","","F","","G","Ab","A"},
-    {"B","","C#","D","D#","E","","F#","","G#","A","A#"},
-    {"C","","D","Eb","E","F","","G","","A","Bb","B"},
-    {"C#","","D#","E","E#","F#","","G#","","A#","B","B#"},
-    {"D","","E","F","F#","G","","A","","B","C","C#"},
-    {"Eb","","F","Gb","G","Ab","","Bb","","C","Db","D"},
-    {"E","","F#","G","G#","A","","B","","C#","D","D#"},
-    {"F","","G","Ab","A","Bb","","C","","D","Eb","E"},
-    {"F#","","G#","A","A#","B","","C#","","D#","E","E#"},
-    {"G","","A","Bb","B","C","","D","","E","F","F#"},
-    {"Ab","","Bb","Cb","C","Db","","Eb","","F","Gb","G"}
-};
-
 static const float basswindow[] = {0.001769, 0.015848, 0.043608, 0.084265, 0.136670, 0.199341, 0.270509, 0.348162, 0.430105, 0.514023, 0.597545, 0.678311, 0.754038, 0.822586, 0.882019, 0.930656, 0.967124, 0.990393, 0.999803, 0.995091, 0.976388, 0.944223, 0.899505, 0.843498, 0.777785, 0.704222, 0.624888, 0.542025, 0.457975, 0.375112, 0.295778, 0.222215, 0.156502, 0.100495, 0.055777, 0.023612, 0.004909, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000};
 static const float treblewindow[] = {0.000350, 0.003144, 0.008717, 0.017037, 0.028058, 0.041719, 0.057942, 0.076638, 0.097701, 0.121014, 0.146447, 0.173856, 0.203090, 0.233984, 0.266366, 0.300054, 0.334860, 0.370590, 0.407044, 0.444018, 0.481304, 0.518696, 0.555982, 0.592956, 0.629410, 0.665140, 0.699946, 0.733634, 0.766016, 0.796910, 0.826144, 0.853553, 0.878986, 0.902299, 0.923362, 0.942058, 0.958281, 0.971942, 0.982963, 0.991283, 0.996856, 0.999650, 0.999650, 0.996856, 0.991283, 0.982963, 0.971942, 0.958281, 0.942058, 0.923362, 0.902299, 0.878986, 0.853553, 0.826144, 0.796910, 0.766016, 0.733634, 0.699946, 0.665140, 0.629410, 0.592956, 0.555982, 0.518696, 0.481304, 0.444018, 0.407044, 0.370590, 0.334860, 0.300054, 0.266366, 0.233984, 0.203090, 0.173856, 0.146447, 0.121014, 0.097701, 0.076638, 0.057942, 0.041719, 0.028058, 0.017037, 0.008717, 0.003144, 0.000350};
 
--- a/nnls-chroma.n3	Mon Nov 02 12:23:00 2015 +0000
+++ b/nnls-chroma.n3	Mon Nov 02 12:35:13 2015 +0000
@@ -6,6 +6,7 @@
 @prefix dc:       <http://purl.org/dc/elements/1.1/> .
 @prefix af:       <http://purl.org/ontology/af/> .
 @prefix foaf:     <http://xmlns.com/foaf/0.1/> .
+@prefix doap: 	  <http://usefulinc.com/ns/doap#> .
 @prefix cc:       <http://web.resource.org/cc/> .
 @prefix :         <#> .
 
@@ -13,21 +14,33 @@
     foaf:maker          <http://www.vamp-plugins.org/doap.rdf#template-generator> ;
     foaf:primaryTopic   <http://vamp-plugins.org/rdf/plugins/nnls-chroma> .
 
+:maker
+    foaf:name "Matthias Mauch" ;
+    foaf:logo <http://vamp-plugins.org/rdf/plugins/makers/qm.png> ;
+    foaf:page <http://c4dm.eecs.qmul.ac.uk/> .
+
 :nnls-chroma a  vamp:PluginLibrary ;
-    vamp:identifier "nnls-chroma"  ; 
+    vamp:identifier "nnls-chroma"  ;
+    dc:title "Chordino and NNLS Chroma" ;
+    dc:description "Harmony and chord extraction plugins by Matthias Mauch at C4DM" ;
     vamp:available_plugin plugbase:chordino ; 
     vamp:available_plugin plugbase:nnls-chroma ; 
     vamp:available_plugin plugbase:tuning ;  
     foaf:page <http://www.isophonics.net/nnls-chroma> ;
+    doap:download-page <http://www.isophonics.net/nnls-chroma> ;
     foaf:page <http://www.omras2.org/> ;
     foaf:page <http://www.matthiasmauch.net/> ; 
+    foaf:maker :maker ;
+    vamp:has_source true ;
+    vamp:has_binary "win32" ;
+    vamp:has_binary "osx" ;
     .
 
 plugbase:chordino a   vamp:Plugin ;
     dc:title              "Chordino" ;
     vamp:name             "Chordino" ;
     dc:description        """Chordino provides a simple chord transcription based on NNLS Chroma (as in the NNLS Chroma plugin). Chord profiles given by the user in the file chord.dict are used to calculate frame-wise chord similarities. Two simple (non-state-of-the-art!) algorithms are available that smooth these to provide a chord transcription: a simple chord change method, and a standard HMM/Viterbi approach.""" ;
-    foaf:maker            [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here
+    foaf:maker            :maker ;
     dc:rights             """GPL""" ;
 #   cc:license            <Place plugin license URI here and uncomment> ; 
     vamp:identifier       "chordino" ;
@@ -42,10 +55,8 @@
     vamp:parameter   plugbase:chordino_param_tuningmode ;
     vamp:parameter   plugbase:chordino_param_whitening ;
     vamp:parameter   plugbase:chordino_param_s ;
-    vamp:parameter   plugbase:chordino_param_boostn ;
 
     vamp:output      plugbase:chordino_output_simplechord ;
-    vamp:output      plugbase:chordino_output_chordnotes ;
     vamp:output      plugbase:chordino_output_harmonicchange ;
     .
 plugbase:chordino_param_useNNLS a  vamp:QuantizedParameter ;
@@ -111,16 +122,6 @@
     vamp:unit           ""  ;
     vamp:default_value   0.7 ;
     vamp:value_names     ();
-
-plugbase:chordino_param_boostn a  vamp:Parameter ;
-    vamp:identifier     "boostn" ;
-    dc:title            "Boost likelihood of the N (no chord) label." ;
-    dc:format           "" ;
-    vamp:min_value       0 ;
-    vamp:max_value       1 ;
-    vamp:unit           ""  ;
-    vamp:default_value   0.1 ;
-    vamp:value_names     ();
     .
 plugbase:chordino_output_simplechord a  vamp:SparseOutput ;
     vamp:identifier       "simplechord" ;
@@ -134,21 +135,6 @@
     vamp:sample_type      vamp:VariableSampleRate ;
     vamp:sample_rate      21.5332 ;
     vamp:computes_event_type   af:ChordSegment ;
-
-plugbase:chordino_output_chordnotes a vamp:SparseOutput ;
-    vamp:identifier       "chordnotes" ;
-    dc:title              "Note Representation of Chord Estimate" ;
-    dc:description        """A simple represenation of the estimated chord with bass note (if applicable) and chord notes."""  ;
-    vamp:fixed_bin_count  "true" ;
-    vamp:unit             "MIDI units" ;
-    a                     vamp:QuantizedOutput ;
-    vamp:quantize_step    1  ;
-    a                 vamp:KnownExtentsOutput ;
-    vamp:min_value    0  ;
-    vamp:max_value    127  ;
-    vamp:bin_count        1 ;
-    vamp:sample_type      vamp:VariableSampleRate ;
-    vamp:computes_event_type   af:Note ;
     .
 plugbase:chordino_output_harmonicchange a  vamp:DenseOutput ;
     vamp:identifier       "harmonicchange" ;
@@ -166,7 +152,7 @@
     dc:title              "NNLS Chroma" ;
     vamp:name             "NNLS Chroma" ;
     dc:description        """This plugin provides a number of features derived from a DFT-based log-frequency amplitude spectrum: some variants of the log-frequency spectrum, including a semitone spectrum derived from approximate transcription using the NNLS algorithm; and based on this semitone spectrum, different chroma features.""" ;
-    foaf:maker            [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here
+    foaf:maker            :maker ;
     dc:rights             """GPL""" ;
 #   cc:license            <Place plugin license URI here and uncomment> ; 
     vamp:identifier       "nnls-chroma" ;
@@ -188,7 +174,6 @@
     vamp:output      plugbase:nnls-chroma_output_chroma ;
     vamp:output      plugbase:nnls-chroma_output_basschroma ;
     vamp:output      plugbase:nnls-chroma_output_bothchroma ;
-    vamp:output      plugbase:nnls-chroma_output_consonance ;
     .
 plugbase:nnls-chroma_param_useNNLS a  vamp:QuantizedParameter ;
     vamp:identifier     "useNNLS" ;
@@ -311,22 +296,11 @@
     vamp:bin_names        ( "A  (bass)" "Bb (bass)" "B  (bass)" "C  (bass)" "C# (bass)" "D  (bass)" "Eb (bass)" "E  (bass)" "F  (bass)" "F# (bass)" "G  (bass)" "Ab (bass)" "A" "Bb" "B" "C" "C#" "D" "Eb" "E" "F" "F#" "G" "Ab");
     vamp:computes_signal_type  af:Chromagram ;
     .
-
-plugbase:nnls-chroma_output_consonance a  vamp:DenseOutput ;
-    vamp:identifier       "consonance" ;
-    dc:title              "Consonance estimate." ;
-    dc:description        """A simple consonance value based on the convolution of a consonance profile with the semitone spectrum."""  ;
-    vamp:fixed_bin_count  "true" ;
-    vamp:unit             "" ;
-    vamp:bin_count        1 ; 
-    vamp:computes_signal_type  af:TonalChangeDetectionFunction;
-    .
-
 plugbase:tuning a   vamp:Plugin ;
     dc:title              "Tuning" ;
     vamp:name             "Tuning" ;
     dc:description        """The tuning plugin can estimate the local and global tuning of piece. The same tuning method is used for the NNLS Chroma and Chordino plugins.""" ;
-    foaf:maker            [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here
+    foaf:maker            :maker ;
     dc:rights             """GPL""" ;
 #   cc:license            <Place plugin license URI here and uncomment> ; 
     vamp:identifier       "tuning" ;
@@ -334,6 +308,7 @@
     owl:versionInfo       "1" ;
     vamp:input_domain     vamp:FrequencyDomain ;
 
+
     vamp:parameter   plugbase:tuning_param_rollon ;
 
     vamp:output      plugbase:tuning_output_tuning ;
@@ -359,10 +334,10 @@
     a                 vamp:KnownExtentsOutput ;
     vamp:min_value    427.47  ;
     vamp:max_value    452.89  ;
-    vamp:bin_count        1 ;
+    vamp:bin_count        0 ;
     vamp:sample_type      vamp:VariableSampleRate ;
     vamp:sample_rate      2.38221e-44 ;
-    vamp:computes_event_type   af:Segment;
+    vamp:computes_event_type   af:MusicSegment;
     .
 plugbase:tuning_output_localtuning a  vamp:DenseOutput ;
     vamp:identifier       "localtuning" ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/releasenotes-0.3.txt	Mon Nov 02 12:35:13 2015 +0000
@@ -0,0 +1,23 @@
+NNLS Chroma 0.3 -- Release Notes
+
+General Description:
+
+A Vamp plugin library for harmony and chord extraction with some features aimed at amateur musicians, and some at music information retrieval researchers.
+It contains the Chordino, NNLS Chroma and Tuning plugins.
+For more information see README or http://isophonics.net/nnls-chroma
+
+Feature changes:
+
+in Chordino: 
+* added Log-Likelihood of Chord Estimate (based on the Viterbi path used for chord estimation),
+* added option for Chris Harte's chord syntax,
+* removed option for non-HMM chord estimation.
+
+in NNLS-Chroma: 
+* removed consonance output.
+
+Bug fixes:
+* renamed dim7 chord to half-diminished (m7b5 and :hdim7, respectively), and added the correct chord label to the diminished chord (was empty before, and hence treated as major chord).
+
+Other:
+* renamed: spectral roll-off parameter to Bass Noise Threshold (in response to Tim Crawfords comment, thanks!)
\ No newline at end of file
--- a/viterbi.cpp	Mon Nov 02 12:23:00 2015 +0000
+++ b/viterbi.cpp	Mon Nov 02 12:35:13 2015 +0000
@@ -2,40 +2,38 @@
 #include "viterbi.h"
 #include <iostream>
 
-std::vector<int> ViterbiPath(std::vector<double> init, std::vector<vector<double> > trans, std::vector<vector<double> > obs, double *delta) {
+std::vector<int> ViterbiPath(std::vector<double> init, std::vector<vector<double> > trans, std::vector<vector<double> > obs, double *delta, vector<double> *scale) {
     
     int nState = init.size();
     int nFrame = obs.size();
-    // cerr << nState << " " << nFrame << endl;
     
     // check for consistency
-    if (trans[0].size() != nState || trans.size() != nState || obs[0].size() != nState) {
+    if ((int)trans[0].size() != nState || (int)trans.size() != nState || (int)obs[0].size() != nState) {
         cerr << "ERROR: matrix sizes inconsistent." << endl;
     }
-        
-    // vector<vector<double> > delta; // "matrix" of conditional probabilities    
+
     vector<vector<int> > psi; //  "matrix" of remembered indices of the best transitions
     vector<int> path = vector<int>(nFrame, nState-1); // the final output path (current assignment arbitrary, makes sense only for Chordino, where nChord-1 is the "no chord" label)
-    vector<double> scale = vector<double>(nFrame, 0); // remembers by how much the vectors in delta are scaled.
     
     double deltasum = 0;
     
     /* initialise first frame */
-    // delta.push_back(init);    
     for (int iState = 0; iState < nState; ++iState) {
         delta[iState] = init[iState] * obs[0][iState];
+//	cerr << "init[" << iState << "] = " << init[iState] << ", obs[0][" << iState << "] = " << obs[0][iState] << endl;
         deltasum += delta[iState];
     }
     for (int iState = 0; iState < nState; ++iState) delta[iState] /= deltasum; // normalise (scale)
-    scale.push_back(1.0/deltasum);
+    scale->push_back(1.0/deltasum);
     psi.push_back(vector<int>(nState,0));
+
+//    cerr << "nState = " << nState << ", deltasum = " << deltasum << endl;
     
     /* rest of the forward step */
     for (int iFrame = 1; iFrame < nFrame; ++iFrame) {
-        // delta.push_back(vector<double>(nState,0));
         deltasum = 0;
         psi.push_back(vector<int>(nState,0));
-        /* every state wants to know which previous state suits him best */
+        /* every state wants to know which previous state suits it best */
         for (int jState = 0; jState < nState; ++jState) {            
             int bestState = nState - 1;
             double bestValue = 0;
@@ -48,7 +46,7 @@
                     }
                 }
             }
-            // cerr << bestState <<" ::: " << bestValue << endl ;
+
             delta[iFrame * nState + jState] = bestValue * obs[iFrame][jState];
             deltasum += delta[iFrame * nState + jState];
             psi[iFrame][jState] = bestState;
@@ -57,21 +55,21 @@
             for (int iState = 0; iState < nState; ++iState) {            
                 delta[iFrame * nState + iState] /= deltasum; // normalise (scale)
             }
-            scale.push_back(1.0/deltasum);
+            scale->push_back(1.0/deltasum);
         } else {
             for (int iState = 0; iState < nState; ++iState) {            
                 delta[iFrame * nState + iState] = 1.0/nState;
             }
-            scale.push_back(1.0);
+            scale->push_back(1.0);
         }
         
     }
     
     /* initialise backward step */
-    int bestValue = 0;
+    double bestValue = 0;
     for (int iState = 0; iState < nState; ++iState) {
         double currentValue = delta[(nFrame-1) * nState + iState];
-        if (currentValue > path[nFrame-1]) {
+        if (currentValue > bestValue) {
             bestValue = currentValue;            
             path[nFrame-1] = iState;
         }
@@ -80,7 +78,6 @@
     /* rest of backward step */
     for (int iFrame = nFrame-2; iFrame > -1; --iFrame) {
         path[iFrame] = psi[iFrame+1][path[iFrame+1]];
-        // cerr << path[iFrame] << endl;
     }    
     
     return path;
--- a/viterbi.h	Mon Nov 02 12:23:00 2015 +0000
+++ b/viterbi.h	Mon Nov 02 12:35:13 2015 +0000
@@ -23,6 +23,6 @@
 #include <string>
 using namespace std;
 
-extern std::vector<int> ViterbiPath(std::vector<double> init, std::vector<vector<double> > trans, std::vector<vector<double> > obs, double *delta);
+extern std::vector<int> ViterbiPath(std::vector<double> init, std::vector<vector<double> > trans, std::vector<vector<double> > obs, double *delta, vector<double> *scale);
 
 #endif
\ No newline at end of file