* First bit of Vamp v2 work -- add an optional duration to features in
authorChris Cannam <cannam@all-day-breakfast.com>
Thu, 17 Jul 2008 08:51:13 +0000 (08:51 +0000)
committerChris Cannam <cannam@all-day-breakfast.com>
Thu, 17 Jul 2008 08:51:13 +0000 (08:51 +0000)
  a backward compatible way.

  Warning: this code is unstable and experimental and may change
  significantly in the coming weeks.

libmain.cpp
plugins/Notes.cpp
plugins/Notes.h
plugins/Silence.cpp
plugins/Silence.h

index 787ef0c..007d209 100644 (file)
 #include "plugins/Tempo.h"
 #include "plugins/Silence.h"
 
+template <typename P>
+class VersionedPluginAdapter : public Vamp::PluginAdapterBase
+{
+public:
+    VersionedPluginAdapter(unsigned int v) : PluginAdapterBase(), m_v(v) { }
+    virtual ~VersionedPluginAdapter() { }
+
+protected:
+    Vamp::Plugin *createPlugin(float inputSampleRate) {
+        P *p = new P(inputSampleRate, m_v);
+        Vamp::Plugin *plugin = dynamic_cast<Vamp::Plugin *>(p);
+        return plugin;
+    }
+    unsigned int m_v;
+};
+
 static Vamp::PluginAdapter<Onset> onsetAdapter;
 static Vamp::PluginAdapter<Pitch> pitchAdapter;
-static Vamp::PluginAdapter<Notes> notesAdapter;
 static Vamp::PluginAdapter<Tempo> tempoAdapter;
-static Vamp::PluginAdapter<Silence> silenceAdapter;
+
+// These two plugins both benefit from the Vamp v2 API if available
+static VersionedPluginAdapter<Notes> *notesAdapter = 0;
+static VersionedPluginAdapter<Silence> *silenceAdapter = 0;
+
+struct Tidy
+{
+    ~Tidy() { delete notesAdapter; delete silenceAdapter; }
+};
+static Tidy tidy;
 
 const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int vampApiVersion,
                                                     unsigned int index)
@@ -37,9 +61,20 @@ const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int vampApiVersion,
     switch (index) {
     case  0: return onsetAdapter.getDescriptor();
     case  1: return pitchAdapter.getDescriptor();
-    case  2: return notesAdapter.getDescriptor();
     case  3: return tempoAdapter.getDescriptor();
-    case  4: return silenceAdapter.getDescriptor();
+
+    case  2: 
+        if (!notesAdapter) {
+            notesAdapter = new VersionedPluginAdapter<Notes>(vampApiVersion);
+        }
+        return notesAdapter->getDescriptor();
+
+    case  4:
+        if (!silenceAdapter) {
+            silenceAdapter = new VersionedPluginAdapter<Silence>(vampApiVersion);
+        }
+        return silenceAdapter->getDescriptor();
+
     default: return 0;
     }
 }
index 7ac5ef9..8f936d5 100644 (file)
@@ -4,7 +4,7 @@
     Vamp feature extraction plugins using Paul Brossier's Aubio library.
 
     Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006 Chris Cannam.
+    This file copyright 2006-2008 Chris Cannam and QMUL.
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License as
@@ -22,8 +22,9 @@ using std::vector;
 using std::cerr;
 using std::endl;
 
-Notes::Notes(float inputSampleRate) :
+Notes::Notes(float inputSampleRate, unsigned int apiVersion) :
     Plugin(inputSampleRate),
+    m_apiVersion(apiVersion),
     m_ibuf(0),
     m_fftgrain(0),
     m_onset(0),
@@ -43,6 +44,10 @@ Notes::Notes(float inputSampleRate) :
     m_avoidLeaps(false),
     m_prevPitch(-1)
 {
+    if (apiVersion == 1) {
+        cerr << "vamp-aubio: WARNING: using compatibility version 1 of the Vamp API for note\n"
+             << "tracker plugin: upgrade your host to v2 for proper duration support" << endl;
+    }
 }
 
 Notes::~Notes()
@@ -83,7 +88,8 @@ Notes::getMaker() const
 int
 Notes::getPluginVersion() const
 {
-    return 1;
+    if (m_apiVersion == 1) return 2;
+    return 3;
 }
 
 string
@@ -320,10 +326,18 @@ Notes::getOutputDescriptors() const
     d.name = "Notes";
     d.unit = "Hz";
     d.hasFixedBinCount = true;
-    d.binCount = 2;
-    d.binNames.push_back("Frequency");
-    d.binNames.push_back("Duration");
-    d.binNames.push_back("Velocity");
+
+    if (m_apiVersion == 1) {
+        d.binCount = 3;
+        d.binNames.push_back("Frequency");
+        d.binNames.push_back("Duration");
+        d.binNames.push_back("Velocity");
+    } else {
+        d.binCount = 2;
+        d.binNames.push_back("Frequency");
+        d.binNames.push_back("Velocity");
+    }
+
     d.hasKnownExtents = false;
     d.isQuantized = false;
     d.sampleType = OutputDescriptor::VariableSampleRate;
@@ -429,9 +443,19 @@ Notes::pushNote(FeatureSet &fs, const Vamp::RealTime &offTime)
     if (m_currentOnset < m_delay) m_currentOnset = m_delay;
     feature.timestamp = m_currentOnset - m_delay;
     feature.values.push_back(freq);
-    feature.values.push_back
-        (Vamp::RealTime::realTime2Frame(offTime, lrintf(m_inputSampleRate)) -
-         Vamp::RealTime::realTime2Frame(m_currentOnset, lrintf(m_inputSampleRate)));
+
+    if (m_apiVersion == 1) {
+        feature.values.push_back
+            (Vamp::RealTime::realTime2Frame
+             (offTime, lrintf(m_inputSampleRate)) -
+             Vamp::RealTime::realTime2Frame
+             (m_currentOnset, lrintf(m_inputSampleRate)));
+        feature.hasDuration = false;
+    } else {
+        feature.hasDuration = true;
+        feature.duration = offTime - m_currentOnset;
+    }
+
     feature.values.push_back(m_currentLevel);
     fs[0].push_back(feature);
 }
index 3fc488b..c8141b9 100644 (file)
@@ -25,7 +25,7 @@
 class Notes : public Vamp::Plugin
 {
 public:
-    Notes(float inputSampleRate);
+    Notes(float inputSampleRate, unsigned int apiVersion);
     virtual ~Notes();
 
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@@ -55,6 +55,7 @@ public:
     FeatureSet getRemainingFeatures();
 
 protected:
+    int m_apiVersion;
     fvec_t *m_ibuf;
     cvec_t *m_fftgrain;
     fvec_t *m_onset;
index c7d2713..7369276 100644 (file)
@@ -4,7 +4,7 @@
     Vamp feature extraction plugins using Paul Brossier's Aubio library.
 
     Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006 Chris Cannam.
+    This file copyright 2006-2008 Chris Cannam and QMUL.
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License as
@@ -21,8 +21,9 @@ using std::vector;
 using std::cerr;
 using std::endl;
 
-Silence::Silence(float inputSampleRate) :
+Silence::Silence(float inputSampleRate, unsigned int apiVersion) :
     Plugin(inputSampleRate),
+    m_apiVersion(apiVersion),
     m_ibuf(0),
     m_pbuf(0),
     m_tmpptrs(0),
@@ -30,6 +31,10 @@ Silence::Silence(float inputSampleRate) :
     m_prevSilent(false),
     m_first(true)
 {
+    if (m_apiVersion == 1) {
+        cerr << "vamp-aubio: WARNING: using compatibility version 1 of the Vamp API for silence\n"
+             << "detector plugin: upgrade your host to v2 for proper duration support" << endl;
+    }
 }
 
 Silence::~Silence()
@@ -66,7 +71,8 @@ Silence::getMaker() const
 int
 Silence::getPluginVersion() const
 {
-    return 1;
+    if (m_apiVersion == 1) return 2;
+    return 3;
 }
 
 string
@@ -150,23 +156,51 @@ Silence::getOutputDescriptors() const
     OutputList list;
 
     OutputDescriptor d;
-    d.identifier = "silencestart";
-    d.name = "Beginnings of Silent Regions";
-    d.description = "Return a single instant at the point where each silent region begins";
-    d.hasFixedBinCount = true;
-    d.binCount = 0;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.sampleRate = 0;
-    list.push_back(d);
 
-    d.identifier = "silenceend";
-    d.name = "Ends of Silent Regions";
-    d.description = "Return a single instant at the point where each silent region ends";
-    d.hasFixedBinCount = true;
-    d.binCount = 0;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.sampleRate = 0;
-    list.push_back(d);
+    if (m_apiVersion == 1) {
+
+        d.identifier = "silencestart";
+        d.name = "Beginnings of Silent Regions";
+        d.description = "Return a single instant at the point where each silent region begins";
+        d.hasFixedBinCount = true;
+        d.binCount = 0;
+        d.hasKnownExtents = false;
+        d.sampleType = OutputDescriptor::VariableSampleRate;
+        d.sampleRate = 0;
+        list.push_back(d);
+
+        d.identifier = "silenceend";
+        d.name = "Ends of Silent Regions";
+        d.description = "Return a single instant at the point where each silent region ends";
+        d.hasFixedBinCount = true;
+        d.binCount = 0;
+        d.hasKnownExtents = false;
+        d.sampleType = OutputDescriptor::VariableSampleRate;
+        d.sampleRate = 0;
+        list.push_back(d);
+
+    } else {
+
+        d.identifier = "silent";
+        d.name = "Silent Regions";
+        d.description = "Return an interval covering each silent region";
+        d.hasFixedBinCount = true;
+        d.binCount = 0;
+        d.hasKnownExtents = false;
+        d.sampleType = OutputDescriptor::VariableSampleRate;
+        d.sampleRate = 0;
+        list.push_back(d);
+
+        d.identifier = "noisy";
+        d.name = "Non-Silent Regions";
+        d.description = "Return an interval covering each non-silent region";
+        d.hasFixedBinCount = true;
+        d.binCount = 0;
+        d.hasKnownExtents = false;
+        d.sampleType = OutputDescriptor::VariableSampleRate;
+        d.sampleRate = 0;
+        list.push_back(d);
+    }
 
     d.identifier = "silencelevel";
     d.name = "Silence Test";
@@ -249,13 +283,30 @@ Silence::process(const float *const *inputBuffers,
         feature.timestamp = featureStamp;
         feature.values.push_back(silent ? 0 : 1);
         returnFeatures[2].push_back(feature);
+
         feature.values.clear();
 
-        if (silent) {
-            returnFeatures[0].push_back(feature);
+        if (m_apiVersion == 1) {
+            if (silent) {
+                returnFeatures[0].push_back(feature);
+            } else {
+                returnFeatures[1].push_back(feature);
+            }
         } else {
-            returnFeatures[1].push_back(feature);
-        }            
+            if (!m_first) {
+                feature.timestamp = m_lastChange;
+                feature.hasDuration = true;
+                feature.duration = featureStamp - m_lastChange;
+                if (silent) {
+                    // becoming silent, so this is a non-silent region
+                    returnFeatures[1].push_back(feature);
+                } else {
+                    // becoming non-silent, so this is a silent region
+                    returnFeatures[0].push_back(feature);
+                }                    
+            }
+            m_lastChange = featureStamp;
+        }
 
         m_prevSilent = silent;
         m_first = false;
@@ -268,12 +319,31 @@ Silence::process(const float *const *inputBuffers,
     m_ibuf->data = m_pbuf->data;
     m_pbuf->data = tmpdata;
 
+    m_lastTimestamp = timestamp;
+
     return returnFeatures;
 }
 
 Silence::FeatureSet
 Silence::getRemainingFeatures()
 {
+    FeatureSet returnFeatures;
+    
+    if (m_prevSilent) {
+        if (m_lastTimestamp > m_lastChange) {
+            Feature feature;
+            feature.hasTimestamp = true;
+            feature.timestamp = m_lastChange;
+            feature.hasDuration = true;
+            feature.duration = m_lastTimestamp - m_lastChange;
+            if (m_prevSilent) {
+                returnFeatures[0].push_back(feature);
+            } else {
+                returnFeatures[1].push_back(feature);
+            }                
+        }
+    }
+
     return FeatureSet();
 }
 
index 35b3fad..eb7c89e 100644 (file)
@@ -23,7 +23,7 @@
 class Silence : public Vamp::Plugin
 {
 public:
-    Silence(float inputSampleRate);
+    Silence(float inputSampleRate, unsigned int apiVersion);
     virtual ~Silence();
 
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@@ -53,6 +53,7 @@ public:
     FeatureSet getRemainingFeatures();
 
 protected:
+    unsigned int m_apiVersion;
     fvec_t *m_ibuf;
     fvec_t *m_pbuf;
     smpl_t **m_tmpptrs;
@@ -62,6 +63,8 @@ protected:
     size_t m_channelCount;
     bool m_prevSilent;
     bool m_first;
+    Vamp::RealTime m_lastChange;
+    Vamp::RealTime m_lastTimestamp;
 };