changeset 190:1982246a3902

* Provide PluginWrapper method for getting hold of a nested wrapper directly (a bit gross, but useful) * Use the above to enable the simple host to adjust timestamps appropriately when printing out results from input domain adapter wrapped plugins
author cannam
date Wed, 17 Sep 2008 13:16:09 +0000
parents 5ce2c3f79a45
children d1bdcd4a226f
files examples/SpectralCentroid.cpp examples/ZeroCrossing.cpp host/vamp-simple-host.cpp vamp-sdk/Plugin.h vamp-sdk/hostext/PluginInputDomainAdapter.cpp vamp-sdk/hostext/PluginInputDomainAdapter.h vamp-sdk/hostext/PluginWrapper.h
diffstat 7 files changed, 112 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/examples/SpectralCentroid.cpp	Wed Sep 17 11:00:51 2008 +0000
+++ b/examples/SpectralCentroid.cpp	Wed Sep 17 13:16:09 2008 +0000
@@ -133,8 +133,10 @@
     return list;
 }
 
+//static int scount = 0;
+
 SpectralCentroid::FeatureSet
-SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime)
+SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
 {
     if (m_stepSize == 0) {
 	cerr << "ERROR: SpectralCentroid::process: "
@@ -143,6 +145,8 @@
 	return FeatureSet();
     }
 
+//    std::cerr << "SpectralCentroid::process: count = " << scount++ << ", timestamp = " << timestamp << ", total power = ";
+
     double numLin = 0.0, numLog = 0.0, denom = 0.0;
 
     for (size_t i = 1; i <= m_blockSize/2; ++i) {
@@ -155,10 +159,10 @@
 	denom += power;
     }
 
+//    std::cerr << denom << std::endl;
+
     FeatureSet returnFeatures;
 
-//    std::cerr << "power " << denom << ", block size " << m_blockSize << std::endl;
-
     if (denom != 0.0) {
 	float centroidLin = float(numLin / denom);
 	float centroidLog = powf(10, float(numLog / denom));
--- a/examples/ZeroCrossing.cpp	Wed Sep 17 11:00:51 2008 +0000
+++ b/examples/ZeroCrossing.cpp	Wed Sep 17 13:16:09 2008 +0000
@@ -41,6 +41,7 @@
 using std::cerr;
 using std::endl;
 
+#include <cmath>
 
 ZeroCrossing::ZeroCrossing(float inputSampleRate) :
     Plugin(inputSampleRate),
@@ -137,6 +138,8 @@
     return list;
 }
 
+//static int scount = 0;
+
 ZeroCrossing::FeatureSet
 ZeroCrossing::process(const float *const *inputBuffers,
                       Vamp::RealTime timestamp)
@@ -148,11 +151,15 @@
 	return FeatureSet();
     }
 
+//    std::cerr << "ZeroCrossing::process: count = " << scount++ << ", timestamp = " << timestamp << ", rms = ";
+
     float prev = m_previousSample;
     size_t count = 0;
 
     FeatureSet returnFeatures;
 
+//    double acc = 0.0;
+
     for (size_t i = 0; i < m_stepSize; ++i) {
 
 	float sample = inputBuffers[0][i];
@@ -173,9 +180,14 @@
 	    returnFeatures[1].push_back(feature);
 	}
 
+//        acc += sample * sample;
+
 	prev = sample;
     }
 
+//    acc /= m_stepSize;
+//    std::cerr << sqrt(acc) << std::endl;
+
     m_previousSample = prev;
 
     Feature feature;
--- a/host/vamp-simple-host.cpp	Wed Sep 17 11:00:51 2008 +0000
+++ b/host/vamp-simple-host.cpp	Wed Sep 17 13:16:09 2008 +0000
@@ -36,7 +36,6 @@
 */
 
 #include "vamp-sdk/PluginHostAdapter.h"
-#include "vamp-sdk/hostext/PluginChannelAdapter.h"
 #include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
 #include "vamp-sdk/hostext/PluginLoader.h"
 #include "vamp/vamp.h"
@@ -59,8 +58,10 @@
 using Vamp::PluginHostAdapter;
 using Vamp::RealTime;
 using Vamp::HostExt::PluginLoader;
+using Vamp::HostExt::PluginWrapper;
+using Vamp::HostExt::PluginInputDomainAdapter;
 
-#define HOST_VERSION "1.1"
+#define HOST_VERSION "1.3"
 
 enum Verbosity {
     PluginIds,
@@ -328,6 +329,10 @@
     int returnValue = 1;
     int progress = 0;
 
+    RealTime rt;
+    PluginWrapper *wrapper = 0;
+    RealTime adjustment = RealTime::zeroTime;
+
     if (outputs.empty()) {
 	cerr << "ERROR: Plugin has no outputs!" << endl;
         goto done;
@@ -365,6 +370,13 @@
         goto done;
     }
 
+    wrapper = dynamic_cast<PluginWrapper *>(plugin);
+    if (wrapper) {
+        PluginInputDomainAdapter *ida =
+            wrapper->getWrapper<PluginInputDomainAdapter>();
+        if (ida) adjustment = ida->getTimestampAdjustment();
+    }
+
     for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
 
         int count;
@@ -391,9 +403,11 @@
             }
         }
 
+        rt = RealTime::frame2RealTime(i, sfinfo.samplerate);
+
         printFeatures
-            (i, sfinfo.samplerate, outputNo, plugin->process
-             (plugbuf, RealTime::frame2RealTime(i, sfinfo.samplerate)),
+            (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
+             sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt),
              out, useFrames);
 
         int pp = progress;
@@ -404,7 +418,10 @@
     }
     if (out) cerr << "\rDone" << endl;
 
-    printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
+    rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate);
+
+    printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
+                  sfinfo.samplerate, outputNo,
                   plugin->getRemainingFeatures(), out, useFrames);
 
     returnValue = 0;
--- a/vamp-sdk/Plugin.h	Wed Sep 17 11:00:51 2008 +0000
+++ b/vamp-sdk/Plugin.h	Wed Sep 17 13:16:09 2008 +0000
@@ -378,9 +378,9 @@
      * If the plugin's inputDomain is TimeDomain, inputBuffers will
      * point to one array of floats per input channel, and each of
      * these arrays will contain blockSize consecutive audio samples
-     * (the host will zero-pad as necessary).  The timestamp will be
-     * the real time in seconds of the start of the supplied block of
-     * samples.
+     * (the host will zero-pad as necessary).  The timestamp in this
+     * case will be the real time in seconds of the start of the
+     * supplied block of samples.
      *
      * If the plugin's inputDomain is FrequencyDomain, inputBuffers
      * will point to one array of floats per input channel, and each
--- a/vamp-sdk/hostext/PluginInputDomainAdapter.cpp	Wed Sep 17 11:00:51 2008 +0000
+++ b/vamp-sdk/hostext/PluginInputDomainAdapter.cpp	Wed Sep 17 13:16:09 2008 +0000
@@ -86,6 +86,8 @@
     size_t getPreferredBlockSize() const;
 
     FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    
+    RealTime getTimestampAdjustment() const;
 
 protected:
     Plugin *m_plugin;
@@ -151,6 +153,13 @@
     return m_impl->process(inputBuffers, timestamp);
 }
 
+RealTime
+PluginInputDomainAdapter::getTimestampAdjustment() const
+{
+    return m_impl->getTimestampAdjustment();
+}
+
+
 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
     m_plugin(plugin),
     m_inputSampleRate(inputSampleRate),
@@ -338,6 +347,17 @@
     return blockSize;
 }
 
+RealTime
+PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
+{
+    if (m_plugin->getInputDomain() == TimeDomain) {
+        return RealTime::zeroTime;
+    } else {
+        return RealTime::frame2RealTime
+            (m_blockSize/2, int(m_inputSampleRate + 0.5));
+    }
+}
+
 Plugin::FeatureSet
 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
                                         RealTime timestamp)
@@ -390,8 +410,7 @@
 
 //    std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
 
-    timestamp = timestamp + RealTime::frame2RealTime
-        (m_blockSize/2, int(m_inputSampleRate + 0.5));
+    timestamp = timestamp + getTimestampAdjustment();
 
 //    std::cerr << " to " << timestamp << std::endl;
 
--- a/vamp-sdk/hostext/PluginInputDomainAdapter.h	Wed Sep 17 11:00:51 2008 +0000
+++ b/vamp-sdk/hostext/PluginInputDomainAdapter.h	Wed Sep 17 13:16:09 2008 +0000
@@ -91,6 +91,29 @@
 
     FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
 
+    /**
+     * Return the amount by which the timestamps supplied to process()
+     * are being incremented when they are passed to the plugin's own
+     * process() implementation.
+     *
+     * The Vamp API mandates that the timestamp passed to the plugin
+     * for time-domain input should be the time of the first sample in
+     * the block, but the timestamp passed for frequency-domain input
+     * should be the timestamp of the centre of the block.
+     *
+     * The PluginInputDomainAdapter adjusts its timestamps properly so
+     * that the plugin receives correct times, but in some
+     * circumstances (such as for establishing the correct timing of
+     * implicitly-timed features, i.e. features without their own
+     * timestamps) the host may need to be aware that this adjustment
+     * is taking place.
+     *
+     * If the plugin requires time-domain input, this function will
+     * return zero.  The result of calling this function before
+     * initialise() has been called is undefined.
+     */
+    RealTime getTimestampAdjustment() const;
+
 protected:
     class Impl;
     Impl *m_impl;
--- a/vamp-sdk/hostext/PluginWrapper.h	Wed Sep 17 11:00:51 2008 +0000
+++ b/vamp-sdk/hostext/PluginWrapper.h	Wed Sep 17 13:16:09 2008 +0000
@@ -94,6 +94,30 @@
 
     FeatureSet getRemainingFeatures();
 
+    /**
+     * Return a pointer to the plugin wrapper of type WrapperType
+     * surrounding this wrapper's plugin, if present.
+     *
+     * This is useful in situations where a plugin is wrapped by
+     * multiple different wrappers (one inside another) and the host
+     * wants to call some wrapper-specific function on one of the
+     * layers without having to care about the order in which they are
+     * wrapped.  For example, the plugin returned by
+     * PluginLoader::loadPlugin may have more than one wrapper; if the
+     * host wanted to query or fine-tune some property of one of them,
+     * it would be hard to do so without knowing the order of the
+     * wrappers.  This function therefore gives direct access to the
+     * wrapper of a particular type.
+     */
+    template <typename WrapperType>
+    WrapperType *getWrapper() {
+        WrapperType *w = dynamic_cast<WrapperType *>(this);
+        if (w) return w;
+        PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin);
+        if (pw) return pw->getWrapper<WrapperType>();
+        return 0;
+    }
+
 protected:
     PluginWrapper(Plugin *plugin); // I take ownership of plugin
     Plugin *m_plugin;