* 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"
 
 #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<Onset> onsetAdapter;
 static Vamp::PluginAdapter<Pitch> pitchAdapter;
-static Vamp::PluginAdapter<Notes> notesAdapter;
 static Vamp::PluginAdapter<Tempo> tempoAdapter;
 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)
 
 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();
     switch (index) {
     case  0: return onsetAdapter.getDescriptor();
     case  1: return pitchAdapter.getDescriptor();
-    case  2: return notesAdapter.getDescriptor();
     case  3: return tempoAdapter.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;
     }
 }
     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.
     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
     
     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;
 
 using std::cerr;
 using std::endl;
 
-Notes::Notes(float inputSampleRate) :
+Notes::Notes(float inputSampleRate, unsigned int apiVersion) :
     Plugin(inputSampleRate),
     Plugin(inputSampleRate),
+    m_apiVersion(apiVersion),
     m_ibuf(0),
     m_fftgrain(0),
     m_onset(0),
     m_ibuf(0),
     m_fftgrain(0),
     m_onset(0),
@@ -43,6 +44,10 @@ Notes::Notes(float inputSampleRate) :
     m_avoidLeaps(false),
     m_prevPitch(-1)
 {
     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()
 }
 
 Notes::~Notes()
@@ -83,7 +88,8 @@ Notes::getMaker() const
 int
 Notes::getPluginVersion() const
 {
 int
 Notes::getPluginVersion() const
 {
-    return 1;
+    if (m_apiVersion == 1) return 2;
+    return 3;
 }
 
 string
 }
 
 string
@@ -320,10 +326,18 @@ Notes::getOutputDescriptors() const
     d.name = "Notes";
     d.unit = "Hz";
     d.hasFixedBinCount = true;
     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;
     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);
     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);
 }
     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:
 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);
     virtual ~Notes();
 
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@@ -55,6 +55,7 @@ public:
     FeatureSet getRemainingFeatures();
 
 protected:
     FeatureSet getRemainingFeatures();
 
 protected:
+    int m_apiVersion;
     fvec_t *m_ibuf;
     cvec_t *m_fftgrain;
     fvec_t *m_onset;
     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.
     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
     
     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;
 
 using std::cerr;
 using std::endl;
 
-Silence::Silence(float inputSampleRate) :
+Silence::Silence(float inputSampleRate, unsigned int apiVersion) :
     Plugin(inputSampleRate),
     Plugin(inputSampleRate),
+    m_apiVersion(apiVersion),
     m_ibuf(0),
     m_pbuf(0),
     m_tmpptrs(0),
     m_ibuf(0),
     m_pbuf(0),
     m_tmpptrs(0),
@@ -30,6 +31,10 @@ Silence::Silence(float inputSampleRate) :
     m_prevSilent(false),
     m_first(true)
 {
     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()
 }
 
 Silence::~Silence()
@@ -66,7 +71,8 @@ Silence::getMaker() const
 int
 Silence::getPluginVersion() const
 {
 int
 Silence::getPluginVersion() const
 {
-    return 1;
+    if (m_apiVersion == 1) return 2;
+    return 3;
 }
 
 string
 }
 
 string
@@ -150,23 +156,51 @@ Silence::getOutputDescriptors() const
     OutputList list;
 
     OutputDescriptor d;
     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";
 
     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.timestamp = featureStamp;
         feature.values.push_back(silent ? 0 : 1);
         returnFeatures[2].push_back(feature);
+
         feature.values.clear();
 
         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 {
         } 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;
 
         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_ibuf->data = m_pbuf->data;
     m_pbuf->data = tmpdata;
 
+    m_lastTimestamp = timestamp;
+
     return returnFeatures;
 }
 
 Silence::FeatureSet
 Silence::getRemainingFeatures()
 {
     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();
 }
 
     return FeatureSet();
 }
 
index 35b3fad..eb7c89e 100644 (file)
@@ -23,7 +23,7 @@
 class Silence : public Vamp::Plugin
 {
 public:
 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);
     virtual ~Silence();
 
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@@ -53,6 +53,7 @@ public:
     FeatureSet getRemainingFeatures();
 
 protected:
     FeatureSet getRemainingFeatures();
 
 protected:
+    unsigned int m_apiVersion;
     fvec_t *m_ibuf;
     fvec_t *m_pbuf;
     smpl_t **m_tmpptrs;
     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;
     size_t m_channelCount;
     bool m_prevSilent;
     bool m_first;
+    Vamp::RealTime m_lastChange;
+    Vamp::RealTime m_lastTimestamp;
 };
 
 
 };