changeset 35:2f5b169e4a3b

Integrate NoteHypothesis class, build fixes
author Chris Cannam
date Thu, 19 Jul 2012 13:46:45 +0100
parents 3fb9c657d86b
children 2a2480689cbf
files CepstralPitchTracker.cpp CepstralPitchTracker.h Makefile.inc NoteHypothesis.cpp NoteHypothesis.h
diffstat 5 files changed, 36 insertions(+), 245 deletions(-) [+]
line wrap: on
line diff
--- a/CepstralPitchTracker.cpp	Fri Jul 13 22:48:02 2012 +0100
+++ b/CepstralPitchTracker.cpp	Thu Jul 19 13:46:45 2012 +0100
@@ -37,161 +37,6 @@
 using std::vector;
 using Vamp::RealTime;
 
-CepstralPitchTracker::Hypothesis::Hypothesis()
-{
-    m_state = New;
-}
-
-CepstralPitchTracker::Hypothesis::~Hypothesis()
-{
-}
-
-bool
-CepstralPitchTracker::Hypothesis::isWithinTolerance(Estimate s) const
-{
-    if (m_pending.empty()) {
-        return true;
-    }
-
-    // check we are within a relatively close tolerance of the last
-    // candidate
-    Estimate last = m_pending[m_pending.size()-1];
-    double r = s.freq / last.freq;
-    int cents = lrint(1200.0 * (log(r) / log(2.0)));
-    if (cents < -60 || cents > 60) return false;
-
-    // and within a slightly bigger tolerance of the current mean
-    double meanFreq = getMeanFrequency();
-    r = s.freq / meanFreq;
-    cents = lrint(1200.0 * (log(r) / log(2.0)));
-    if (cents < -80 || cents > 80) return false;
-    
-    return true;
-}
-
-bool
-CepstralPitchTracker::Hypothesis::isOutOfDateFor(Estimate s) const
-{
-    if (m_pending.empty()) return false;
-
-    return ((s.time - m_pending[m_pending.size()-1].time) > 
-            RealTime::fromMilliseconds(40));
-}
-
-bool 
-CepstralPitchTracker::Hypothesis::isSatisfied() const
-{
-    if (m_pending.empty()) return false;
-    
-    double meanConfidence = 0.0;
-    for (int i = 0; i < m_pending.size(); ++i) {
-        meanConfidence += m_pending[i].confidence;
-    }
-    meanConfidence /= m_pending.size();
-
-    int lengthRequired = 10000;
-    if (meanConfidence > 0.0) {
-        lengthRequired = int(2.0 / meanConfidence + 0.5);
-    }
-
-    return (m_pending.size() > lengthRequired);
-}
-
-bool
-CepstralPitchTracker::Hypothesis::accept(Estimate s)
-{
-    bool accept = false;
-
-    switch (m_state) {
-
-    case New:
-        m_state = Provisional;
-        accept = true;
-        break;
-
-    case Provisional:
-        if (isOutOfDateFor(s)) {
-            m_state = Rejected;
-        } else if (isWithinTolerance(s)) {
-            accept = true;
-        }
-        break;
-        
-    case Satisfied:
-        if (isOutOfDateFor(s)) {
-            m_state = Expired;
-        } else if (isWithinTolerance(s)) {
-            accept = true;
-        }
-        break;
-
-    case Rejected:
-        break;
-
-    case Expired:
-        break;
-    }
-
-    if (accept) {
-        m_pending.push_back(s);
-        if (m_state == Provisional && isSatisfied()) {
-            m_state = Satisfied;
-        }
-    }
-
-    return accept;
-}        
-
-CepstralPitchTracker::Hypothesis::State
-CepstralPitchTracker::Hypothesis::getState() const
-{
-    return m_state;
-}
-
-CepstralPitchTracker::Hypothesis::Estimates
-CepstralPitchTracker::Hypothesis::getAcceptedEstimates() const
-{
-    if (m_state == Satisfied || m_state == Expired) {
-        return m_pending;
-    } else {
-        return Estimates();
-    }
-}
-
-double
-CepstralPitchTracker::Hypothesis::getMeanFrequency() const
-{
-    double acc = 0.0;
-    for (int i = 0; i < m_pending.size(); ++i) {
-        acc += m_pending[i].freq;
-    }
-    acc /= m_pending.size();
-    return acc;
-}
-
-CepstralPitchTracker::Hypothesis::Note
-CepstralPitchTracker::Hypothesis::getAveragedNote() const
-{
-    Note n;
-
-    if (!(m_state == Satisfied || m_state == Expired)) {
-        n.freq = 0.0;
-        n.time = RealTime::zeroTime;
-        n.duration = RealTime::zeroTime;
-        return n;
-    }
-
-    n.time = m_pending.begin()->time;
-
-    Estimates::const_iterator i = m_pending.end();
-    --i;
-    n.duration = i->time - n.time;
-
-    // just mean frequency for now, but this isn't at all right perceptually
-    n.freq = getMeanFrequency();
-    
-    return n;
-}
 
 CepstralPitchTracker::CepstralPitchTracker(float inputSampleRate) :
     Plugin(inputSampleRate),
@@ -320,8 +165,6 @@
 {
     OutputList outputs;
 
-    int n = 0;
-
     OutputDescriptor d;
 
     d.identifier = "f0";
@@ -391,11 +234,11 @@
 }
 
 void
-CepstralPitchTracker::addFeaturesFrom(Hypothesis h, FeatureSet &fs)
+CepstralPitchTracker::addFeaturesFrom(NoteHypothesis h, FeatureSet &fs)
 {
-    Hypothesis::Estimates es = h.getAcceptedEstimates();
+    NoteHypothesis::Estimates es = h.getAcceptedEstimates();
 
-    for (int i = 0; i < es.size(); ++i) {
+    for (int i = 0; i < (int)es.size(); ++i) {
 	Feature f;
 	f.hasTimestamp = true;
 	f.timestamp = es[i].time;
@@ -406,7 +249,7 @@
     Feature nf;
     nf.hasTimestamp = true;
     nf.hasDuration = true;
-    Hypothesis::Note n = h.getAveragedNote();
+    NoteHypothesis::Note n = h.getAveragedNote();
     nf.timestamp = n.time;
     nf.duration = n.duration;
     nf.values.push_back(n.freq);
@@ -422,7 +265,7 @@
         // average according to the vertical filter length
         for (int j = -m_vflen/2; j <= m_vflen/2; ++j) {
             int ix = i + m_binFrom + j;
-            if (ix >= 0 && ix < m_blockSize) {
+            if (ix >= 0 && ix < (int)m_blockSize) {
                 v += cep[ix];
                 ++n;
             }
@@ -575,24 +418,19 @@
         std::cerr << "magmean = " << magmean << ", confidence = " << confidence << std::endl;
     }
 
-    Hypothesis::Estimate e;
+    NoteHypothesis::Estimate e;
     e.freq = peakfreq;
     e.time = timestamp;
     e.confidence = confidence;
 
-//    m_good.advanceTime();
-    for (int i = 0; i < m_possible.size(); ++i) {
-//        m_possible[i].advanceTime();
-    }
-
     if (!m_good.accept(e)) {
 
         int candidate = -1;
         bool accepted = false;
 
-        for (int i = 0; i < m_possible.size(); ++i) {
+        for (int i = 0; i < (int)m_possible.size(); ++i) {
             if (m_possible[i].accept(e)) {
-                if (m_possible[i].getState() == Hypothesis::Satisfied) {
+                if (m_possible[i].getState() == NoteHypothesis::Satisfied) {
                     accepted = true;
                     candidate = i;
                 }
@@ -601,31 +439,31 @@
         }
 
         if (!accepted) {
-            Hypothesis h;
+            NoteHypothesis h;
             h.accept(e); //!!! must succeed as h is new, so perhaps there should be a ctor for this
             m_possible.push_back(h);
         }
 
-        if (m_good.getState() == Hypothesis::Expired) {
+        if (m_good.getState() == NoteHypothesis::Expired) {
             addFeaturesFrom(m_good, fs);
         }
         
-        if (m_good.getState() == Hypothesis::Expired ||
-            m_good.getState() == Hypothesis::Rejected) {
+        if (m_good.getState() == NoteHypothesis::Expired ||
+            m_good.getState() == NoteHypothesis::Rejected) {
             if (candidate >= 0) {
                 m_good = m_possible[candidate];
             } else {
-                m_good = Hypothesis();
+                m_good = NoteHypothesis();
             }
         }
 
         // reap rejected/expired hypotheses from possible list
         Hypotheses toReap = m_possible;
         m_possible.clear();
-        for (int i = 0; i < toReap.size(); ++i) {
-            Hypothesis h = toReap[i];
-            if (h.getState() != Hypothesis::Rejected && 
-                h.getState() != Hypothesis::Expired) {
+        for (int i = 0; i < (int)toReap.size(); ++i) {
+            NoteHypothesis h = toReap[i];
+            if (h.getState() != NoteHypothesis::Rejected && 
+                h.getState() != NoteHypothesis::Expired) {
                 m_possible.push_back(h);
             }
         }
@@ -639,7 +477,7 @@
 CepstralPitchTracker::getRemainingFeatures()
 {
     FeatureSet fs;
-    if (m_good.getState() == Hypothesis::Satisfied) {
+    if (m_good.getState() == NoteHypothesis::Satisfied) {
         addFeaturesFrom(m_good, fs);
     }
     return fs;
--- a/CepstralPitchTracker.h	Fri Jul 13 22:48:02 2012 +0100
+++ b/CepstralPitchTracker.h	Thu Jul 19 13:46:45 2012 +0100
@@ -22,11 +22,13 @@
     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#ifndef _CEPSTRUM_PITCH_H_
-#define _CEPSTRUM_PITCH_H_
+#ifndef _CEPSTRAL_PITCH_H_
+#define _CEPSTRAL_PITCH_H_
 
 #include <vamp-sdk/Plugin.h>
 
+#include "NoteHypothesis.h"
+
 class CepstralPitchTracker : public Vamp::Plugin
 {
 public:
@@ -76,54 +78,11 @@
     int m_binTo;
     int m_bins; // count of "interesting" bins, those returned in m_cepOutput
 
-    class Hypothesis {
+    typedef std::vector<NoteHypothesis> Hypotheses;
+    Hypotheses m_possible;
+    NoteHypothesis m_good;
 
-    public:
-        struct Estimate {
-            double freq;
-            Vamp::RealTime time;
-            double confidence;
-        };
-        typedef std::vector<Estimate> Estimates;
-
-        struct Note {
-            double freq;
-            Vamp::RealTime time;
-            Vamp::RealTime duration;
-        };
-        
-        Hypothesis();
-        ~Hypothesis();
-
-        enum State {
-            New,
-            Provisional,
-            Satisfied,
-            Rejected,
-            Expired
-        };
-
-        bool accept(Estimate);
-
-        State getState() const;
-        Estimates getAcceptedEstimates() const;
-        Note getAveragedNote() const;
-
-    private:
-        bool isWithinTolerance(Estimate) const;
-        bool isOutOfDateFor(Estimate) const;
-        bool isSatisfied() const;
-        double getMeanFrequency() const;
-
-        State m_state;
-        Estimates m_pending;
-    };
-
-    typedef std::vector<Hypothesis> Hypotheses;
-    Hypotheses m_possible;
-    Hypothesis m_good;
-
-    void addFeaturesFrom(Hypothesis h, FeatureSet &fs);
+    void addFeaturesFrom(NoteHypothesis h, FeatureSet &fs);
 
     void filter(const double *in, double *out);
     double cubicInterpolate(const double[4], double);
--- a/Makefile.inc	Fri Jul 13 22:48:02 2012 +0100
+++ b/Makefile.inc	Thu Jul 19 13:46:45 2012 +0100
@@ -8,9 +8,11 @@
 CXXFLAGS	:= $(CXXFLAGS) 
 LDFLAGS		:= $(LDFLAGS)
 
-HEADERS := CepstralPitchTracker.h
+HEADERS := CepstralPitchTracker.h \
+	   NoteHypothesis.h
 
 SOURCES := CepstralPitchTracker.cpp \
+	   NoteHypothesis.cpp \
            libmain.cpp
 
 OBJECTS := $(SOURCES:.cpp=.o)
--- a/NoteHypothesis.cpp	Fri Jul 13 22:48:02 2012 +0100
+++ b/NoteHypothesis.cpp	Thu Jul 19 13:46:45 2012 +0100
@@ -5,9 +5,7 @@
 
 #include <cmath>
 
-#include "system/sysutils.h"
-
-namespace Turbot {
+using Vamp::RealTime;
 
 NoteHypothesis::NoteHypothesis()
 {
@@ -166,5 +164,3 @@
     return n;
 }
 
-}
-
--- a/NoteHypothesis.h	Fri Jul 13 22:48:02 2012 +0100
+++ b/NoteHypothesis.h	Thu Jul 19 13:46:45 2012 +0100
@@ -4,11 +4,9 @@
 #ifndef _NOTE_HYPOTHESIS_H_
 #define _NOTE_HYPOTHESIS_H_
 
-#include "base/RealTime.h"
+#include "vamp-sdk/RealTime.h"
 #include <vector>
 
-namespace Turbot {
-
 /**
  * An agent used to test an incoming series of instantaneous pitch
  * estimates to see whether they fit a consistent single-note
@@ -50,13 +48,13 @@
 
     struct Estimate {
         Estimate() : freq(0), time(), confidence(0) { }
-        Estimate(double _f, RealTime _t, double _c) :
+        Estimate(double _f, Vamp::RealTime _t, double _c) :
             freq(_f), time(_t), confidence(_c) { }
         bool operator==(const Estimate &e) const {
             return e.freq == freq && e.time == time && e.confidence == confidence;
         }
 	double freq;
-	RealTime time;
+        Vamp::RealTime time;
 	double confidence;
     };
     typedef std::vector<Estimate> Estimates;
@@ -83,14 +81,14 @@
 
     struct Note {
         Note() : freq(0), time(), duration() { }
-        Note(double _f, RealTime _t, RealTime _d) :
+        Note(double _f, Vamp::RealTime _t, Vamp::RealTime _d) :
             freq(_f), time(_t), duration(_d) { }
         bool operator==(const Note &e) const {
             return e.freq == freq && e.time == time && e.duration == duration;
         }
 	double freq;
-	RealTime time;
-	RealTime duration;
+	Vamp::RealTime time;
+	Vamp::RealTime duration;
     };
     
     /**
@@ -112,6 +110,4 @@
     Estimates m_pending;
 };
 
-}
-
 #endif