changeset 88:fc28c50caace matthiasm-plugin

merge
author Matthias Mauch <mail@matthiasmauch.net>
date Wed, 01 Dec 2010 21:18:49 +0900
parents e8ceb7d3bd4f (current diff) f568555390f1 (diff)
children 7af5312e66f8
files
diffstat 9 files changed, 143 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/Chordino.cpp	Mon Nov 15 11:01:56 2010 +0900
+++ b/Chordino.cpp	Wed Dec 01 21:18:49 2010 +0900
@@ -30,9 +30,15 @@
 const bool debug_on = false;
 
 Chordino::Chordino(float inputSampleRate) :
-    NNLSBase(inputSampleRate)
+    NNLSBase(inputSampleRate),
+    m_chorddict(0),
+    m_chordnotes(0),
+    m_chordnames(0)    
 {
     if (debug_on) cerr << "--> Chordino" << endl;
+    // get the *chord* dictionary from file (if the file exists)
+    m_chordnames = chordDictionary(&m_chorddict, &m_chordnotes);
+    
 }
 
 Chordino::~Chordino()
@@ -182,6 +188,24 @@
     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.unit = "MIDI units";
+    chordnotes.hasFixedBinCount = true;
+    chordnotes.binCount = 1;
+    chordnotes.hasKnownExtents = true;
+    chordnotes.minValue = 0;
+    chordnotes.maxValue = 127;
+    chordnotes.isQuantized = true;
+    chordnotes.quantizeStep = 1;
+    chordnotes.sampleType = OutputDescriptor::VariableSampleRate;
+    chordnotes.hasDuration = true;
+    chordnotes.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
+    list.push_back(chordnotes);
+    m_outputChordnotes = index++;
+    
     OutputDescriptor d8;
     d8.identifier = "harmonicchange";
     d8.name = "Harmonic Change Value";
@@ -488,6 +512,7 @@
     }
     cerr << "done." << endl;
 		
+    vector<Feature> oldnotes;
 
     // bool m_useHMM = true; // this will go into the chordino header file.
 	if (m_useHMM == 1.0) {
@@ -520,12 +545,28 @@
         for (int iFrame = 1; iFrame < 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 < 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 < 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);
+                }
             }
             /* calculating simple chord change prob */            
             for (int iChord = 0; iChord < nChord; iChord++) {
@@ -678,6 +719,20 @@
                 oldChord = maxChord;
                 chord_feature.label = m_chordnames[maxChordIndex];
                 fsOut[m_outputChords].push_back(chord_feature);
+                for (int iNote = 0; iNote < 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 < 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++;
         }
@@ -687,6 +742,12 @@
     chord_feature.timestamp = timestamps[timestamps.size()-1];
     chord_feature.label = "N";
     fsOut[m_outputChords].push_back(chord_feature);
+    
+    for (int iNote = 0; iNote < oldnotes.size(); ++iNote) { // finish duration of old chord
+        oldnotes[iNote].duration = oldnotes[iNote].duration + timestamps[timestamps.size()-1];
+        fsOut[m_outputChordnotes].push_back(oldnotes[iNote]);
+    }
+    
     cerr << "done." << endl;
     
     for (int iFrame = 0; iFrame < nFrame; iFrame++) {
--- a/Chordino.h	Mon Nov 15 11:01:56 2010 +0900
+++ b/Chordino.h	Wed Dec 01 21:18:49 2010 +0900
@@ -46,7 +46,11 @@
 
 protected:
     mutable int m_outputChords;
+    mutable int m_outputChordnotes;
     mutable int m_outputHarmonicChange;
+    vector<float> m_chorddict;
+    vector<vector<int> > m_chordnotes;
+    vector<string> m_chordnames;
 };
 
 
--- a/NNLSBase.cpp	Mon Nov 15 11:01:56 2010 +0900
+++ b/NNLSBase.cpp	Wed Dec 01 21:18:49 2010 +0900
@@ -44,8 +44,6 @@
     m_kernelNoteIndex(0),
     m_dict(0),
     m_tuneLocal(0),
-    m_chorddict(0),
-    m_chordnames(0),
     m_doNormalizeChroma(0),
     m_rollon(0),
 	m_s(0.7),
@@ -60,9 +58,6 @@
     m_dict = new float[nNote * 84];
     for (unsigned i = 0; i < nNote * 84; ++i) m_dict[i] = 0.0;
     dictionaryMatrix(m_dict, 0.7);
-	
-    // get the *chord* dictionary from file (if the file exists)
-    m_chordnames = chordDictionary(&m_chorddict);
 }
 
 
--- a/NNLSBase.h	Mon Nov 15 11:01:56 2010 +0900
+++ b/NNLSBase.h	Wed Dec 01 21:18:49 2010 +0900
@@ -73,8 +73,6 @@
     vector<int> m_kernelNoteIndex;
     float *m_dict;
     bool m_tuneLocal;
-    vector<float> m_chorddict;
-    vector<string> m_chordnames;
     float m_doNormalizeChroma;
     float m_rollon;
     vector<float> hw;
--- a/NNLSChroma.cpp	Mon Nov 15 11:01:56 2010 +0900
+++ b/NNLSChroma.cpp	Wed Dec 01 21:18:49 2010 +0900
@@ -171,6 +171,21 @@
     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++;
+  
     return list;
 }
 
@@ -211,6 +226,9 @@
 NNLSChroma::FeatureSet
 NNLSChroma::getRemainingFeatures()
 {
+    
+    float consonancepattern[24] = {0,-1,-1,1,1,1,-1,1,1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,-1,-1};
+    for (int i = 0; i< 12; ++i) cerr << consonancepattern[i]<< endl; 
     if (debug_on) cerr << "--> getRemainingFeatures" << endl;
     FeatureSet fsOut;
     if (m_logSpectrum.size() == 0) return fsOut;
@@ -256,6 +274,7 @@
         f2.timestamp = f1.timestamp;
         f2.values.push_back(0.0); f2.values.push_back(0.0); // set lower edge to zero
 		
+		
         if (m_tuneLocal) {
             intShift = floor(m_localTuning[count] * 3);
             floatShift = m_localTuning[count] * 3 - intShift; // floatShift is a really bad name for this
@@ -316,7 +335,8 @@
         Feature f4; // treble chromagram
         Feature f5; // bass chromagram
         Feature f6; // treble and bass chromagram
-	
+	    Feature consonance;
+	    
         f3.hasTimestamp = true;
         f3.timestamp = f2.timestamp;
 	        
@@ -329,6 +349,9 @@
         f6.hasTimestamp = true;
         f6.timestamp = f2.timestamp;
 	        
+        consonance.hasTimestamp = true;
+        consonance.timestamp = f2.timestamp;
+	    
         float b[nNote];
 	
         bool some_b_greater_zero = false;
@@ -402,7 +425,20 @@
         } else {
             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];
+            float tempconsonance = 0;
+            for (int jSemitone = 1; jSemitone < 24; ++jSemitone) {
+                tempconsonance += f3.values[iSemitone+jSemitone] * (consonancepattern[jSemitone]);
+            }
+            consonance.values[0] += (f3.values[iSemitone] * tempconsonance);
+        }
+        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 
@@ -465,6 +501,7 @@
         fsOut[m_outputChroma].push_back(f4);
         fsOut[m_outputBassChroma].push_back(f5);
         fsOut[m_outputBothChroma].push_back(f6);
+        fsOut[m_outputConsonance].push_back(consonance);
         count++;
     }
     cerr << "done." << endl;
--- a/NNLSChroma.h	Mon Nov 15 11:01:56 2010 +0900
+++ b/NNLSChroma.h	Wed Dec 01 21:18:49 2010 +0900
@@ -50,6 +50,7 @@
     mutable int m_outputChroma;
     mutable int m_outputBassChroma;
     mutable int m_outputBothChroma;
+    mutable int m_outputConsonance;
 };
 
 
--- a/chromamethods.cpp	Mon Nov 15 11:01:56 2010 +0900
+++ b/chromamethods.cpp	Wed Dec 01 21:18:49 2010 +0900
@@ -277,8 +277,8 @@
     return path;
 }
 
-vector<string> chordDictionary(vector<float> *mchorddict) {
-
+vector<string> chordDictionary(vector<float> *mchorddict, vector<vector<int> > *m_chordnotes) {    
+    
     typedef tokenizer<char_separator<char> > Tok;
     char_separator<char> sep(",; ","=");
 
@@ -310,7 +310,7 @@
     vector<string> loadedChordNames;
     vector<float> loadedChordDict;
     if (chordDictFile.is_open()) {
-        while (std::getline(chordDictFile, line)) { // loop over lines in chord.dict file		
+        while (std::getline(chordDictFile, line)) { // loop over lines in chord.dict file	            	
             // first, get the chord definition
             string chordType;
             vector<float> tempPCVector;			
@@ -333,7 +333,8 @@
                 }
 					
                 // now make all 12 chords of every type
-                for (unsigned iSemitone = 0; iSemitone < 12; iSemitone++) {				
+                for (unsigned iSemitone = 0; iSemitone < 12; iSemitone++) {	
+                    vector<int> tempchordnotes;			
                     // add bass slash notation
                     string slashNotation = "";
                     for (unsigned kSemitone = 1; kSemitone < 12; kSemitone++) {
@@ -341,18 +342,21 @@
                             slashNotation = bassnames[iSemitone][kSemitone];
                         }
                     }
+                    if (slashNotation=="") tempchordnotes.push_back(MIDI_basenote + (iSemitone+12) % 12);
                     for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) { // bass pitch classes
                         // cerr << ((kSemitone - iSemitone + 12) % 12) << endl;
                         float bassValue = 0;
                         if (tempPCVector[(kSemitone - iSemitone + 12) % 12]==1) {
                             bassValue = 1;
+                            tempchordnotes.push_back(MIDI_basenote + (kSemitone+12) % 12);
                         } else {
                             if (tempPCVector[((kSemitone - iSemitone + 12) % 12) + 12] == 1) bassValue = 0.5;
                         }
-                        loadedChordDict.push_back(bassValue);
+                        loadedChordDict.push_back(bassValue);                        
                     }
                     for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) { // chord pitch classes
                         loadedChordDict.push_back(tempPCVector[((kSemitone - iSemitone + 12) % 12) + 12]);
+                        if (tempPCVector[((kSemitone - iSemitone + 12) % 12) + 12] > 0) tempchordnotes.push_back(MIDI_basenote + (kSemitone+12+6) % 12 - 6 + 24);
                     }
                     ostringstream os;				
                     if (slashNotation.empty()) {
@@ -361,7 +365,13 @@
                         os << notenames[12+iSemitone] << chordType << "/" << slashNotation;
                     }
                     // cerr << os.str() << endl;
-                    loadedChordNames.push_back(os.str());
+                    loadedChordNames.push_back(os.str());                
+                    
+                    m_chordnotes->push_back(tempchordnotes);
+                    for (int iNote = 0; iNote < tempchordnotes.size(); ++iNote) {
+                        cerr << tempchordnotes[iNote] << " ";
+                    }
+                    cerr << endl;
                 }
             }
         }
@@ -369,7 +379,8 @@
         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);
-	
+        vector<int> tempchordvector;
+        m_chordnotes->push_back(tempchordvector);
         float exponent = 2.0;
         float boostN = 1.1;
         
--- a/chromamethods.h	Mon Nov 15 11:01:56 2010 +0900
+++ b/chromamethods.h	Wed Dec 01 21:18:49 2010 +0900
@@ -22,13 +22,14 @@
 #include <vector>
 #include <string>
 
-const int nBPS = 5; // bins per semitone
+const int nBPS = 3; // bins per semitone
 const int nOctave = 7;
 const int nNote = nOctave * 12 * nBPS + 2 * (nBPS/2+1); // a core over all octaves, plus some overlap at top and bottom
+const int MIDI_basenote = 45;
 
 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);
+extern std::vector<std::string> chordDictionary(std::vector<float> *mchorddict, std::vector<std::vector<int> > *m_chordnotes);
 extern bool logFreqMatrix(int fs, int blocksize, float *outmatrix);
 
 static const char* notenames[24] = {
--- a/nnls-chroma.n3	Mon Nov 15 11:01:56 2010 +0900
+++ b/nnls-chroma.n3	Wed Dec 01 21:18:49 2010 +0900
@@ -44,6 +44,7 @@
     vamp:parameter   plugbase:chordino_param_s ;
 
     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 ;
@@ -122,6 +123,21 @@
     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" ;