changeset 890:4cbf8c6a462d tony_integration

Merge from branch tonioni
author Chris Cannam
date Tue, 11 Mar 2014 17:30:35 +0000
parents 862fe7b20df7 (current diff) 0c8218b2d84a (diff)
children 8962f80f5d8e
files transform/FeatureExtractionModelTransformer.cpp
diffstat 8 files changed, 209 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/data/model/Model.h	Tue Jan 28 15:01:54 2014 +0000
+++ b/data/model/Model.h	Tue Mar 11 17:30:35 2014 +0000
@@ -216,7 +216,7 @@
     virtual QString toDelimitedDataString(QString delimiter) const {
         return toDelimitedDataString(delimiter, getStartFrame(), getEndFrame());
     }
-    virtual QString toDelimitedDataString(QString, size_t f0, size_t f1) const {
+    virtual QString toDelimitedDataString(QString, size_t /* f0 */, size_t /* f1 */) const {
         return "";
     }
 
--- a/svcore.pro	Tue Jan 28 15:01:54 2014 +0000
+++ b/svcore.pro	Tue Mar 11 17:30:35 2014 +0000
@@ -5,6 +5,10 @@
     include(config.pri)
 }
 !exists(config.pri) {
+
+    CONFIG += release
+    DEFINES += NDEBUG BUILD_RELEASE NO_TIMING
+
     win32-g++ {
         INCLUDEPATH += ../sv-dependency-builds/win32-mingw/include
         LIBS += -L../sv-dependency-builds/win32-mingw/lib
--- a/transform/FeatureExtractionModelTransformer.cpp	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/FeatureExtractionModelTransformer.cpp	Tue Mar 11 17:30:35 2014 +0000
@@ -213,14 +213,14 @@
     }
 
     for (int j = 0; j < (int)m_transforms.size(); ++j) {
-        createOutputModel(j);
+        createOutputModels(j);
     }
 
     return true;
 }
 
 void
-FeatureExtractionModelTransformer::createOutputModel(int n)
+FeatureExtractionModelTransformer::createOutputModels(int n)
 {
     DenseTimeValueModel *input = getConformingInput();
 
@@ -232,11 +232,14 @@
     int binCount = 1;
     float minValue = 0.0, maxValue = 0.0;
     bool haveExtents = false;
-    
-    if (m_descriptors[n]->hasFixedBinCount) {
+    bool haveBinCount = m_descriptors[n]->hasFixedBinCount;
+
+    if (haveBinCount) {
 	binCount = m_descriptors[n]->binCount;
     }
 
+    m_needAdditionalModels[n] = false;
+
 //    cerr << "FeatureExtractionModelTransformer: output bin count "
 //	      << binCount << endl;
 
@@ -401,10 +404,27 @@
         // model.
 
         // Anything that is not a 1D, note, or interval model and that
-        // has a variable sample rate is also treated as a sparse time
-        // value model regardless of its bin count, because we lack a
+        // has a variable sample rate is treated as a set of sparse
+        // time value models, one per output bin, because we lack a
         // sparse 3D model.
 
+        // Anything that is not a 1D, note, or interval model and that
+        // has a fixed sample rate but an unknown number of values per
+        // result is also treated as a set of sparse time value models.
+
+        // For sets of sparse time value models, we create a single
+        // model first as the "standard" output and then create models
+        // for bins 1+ in the additional model map (mapping the output
+        // descriptor to a list of models indexed by bin-1). But we
+        // don't create the additional models yet, as this case has to
+        // work even if the number of bins is unknown at this point --
+        // we create an additional model (copying its parameters from
+        // the default one) each time a new bin is encountered.
+
+        if (!haveBinCount || binCount > 1) {
+            m_needAdditionalModels[n] = true;
+        }
+
         SparseTimeValueModel *model;
         if (haveExtents) {
             model = new SparseTimeValueModel
@@ -463,6 +483,68 @@
     }
 }
 
+FeatureExtractionModelTransformer::Models
+FeatureExtractionModelTransformer::getAdditionalOutputModels()
+{
+    Models mm;
+    for (AdditionalModelMap::iterator i = m_additionalModels.begin();
+         i != m_additionalModels.end(); ++i) {
+        for (std::map<int, SparseTimeValueModel *>::iterator j =
+                 i->second.begin();
+             j != i->second.end(); ++j) {
+            SparseTimeValueModel *m = j->second;
+            if (m) mm.push_back(m);
+        }
+    }
+    return mm;
+}
+
+bool
+FeatureExtractionModelTransformer::willHaveAdditionalOutputModels()
+{
+    for (std::map<int, bool>::const_iterator i =
+             m_needAdditionalModels.begin(); 
+         i != m_needAdditionalModels.end(); ++i) {
+        if (i->second) return true;
+    }
+    return false;
+}
+
+SparseTimeValueModel *
+FeatureExtractionModelTransformer::getAdditionalModel(int n, int binNo)
+{
+    std::cerr << "getAdditionalModel(" << n << ", " << binNo << ")" << std::endl;
+
+    if (binNo == 0) {
+        std::cerr << "Internal error: binNo == 0 in getAdditionalModel (should be using primary model)" << std::endl;
+        return 0;
+    }
+
+    if (!m_needAdditionalModels[n]) return 0;
+    if (!isOutput<SparseTimeValueModel>(n)) return 0;
+    if (m_additionalModels[n][binNo]) return m_additionalModels[n][binNo];
+
+    std::cerr << "getAdditionalModel(" << n << ", " << binNo << "): creating" << std::endl;
+
+    SparseTimeValueModel *baseModel = getConformingOutput<SparseTimeValueModel>(n);
+    if (!baseModel) return 0;
+
+    std::cerr << "getAdditionalModel(" << n << ", " << binNo << "): (from " << baseModel << ")" << std::endl;
+
+    SparseTimeValueModel *additional =
+        new SparseTimeValueModel(baseModel->getSampleRate(),
+                                 baseModel->getResolution(),
+                                 baseModel->getValueMinimum(),
+                                 baseModel->getValueMaximum(),
+                                 false);
+
+    additional->setScaleUnits(baseModel->getScaleUnits());
+    additional->setRDFTypeURI(baseModel->getRDFTypeURI());
+
+    m_additionalModels[n][binNo] = additional;
+    return additional;
+}
+
 DenseTimeValueModel *
 FeatureExtractionModelTransformer::getConformingInput()
 {
@@ -487,7 +569,7 @@
     Transform primaryTransform = m_transforms[0];
 
     while (!input->isReady() && !m_abandoned) {
-        SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl;
+        cerr << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl;
         usleep(500000);
     }
     if (m_abandoned) return;
@@ -814,7 +896,17 @@
                 label = QString("[%1] %2").arg(i+1).arg(label);
             }
 
-            model->addPoint(SparseTimeValueModel::Point(frame, value, label));
+            SparseTimeValueModel *targetModel = model;
+
+            if (m_needAdditionalModels[n] && i > 0) {
+                targetModel = getAdditionalModel(n, i);
+                if (!targetModel) targetModel = model;
+                std::cerr << "adding point to model " << targetModel
+                          << " for output " << n << " bin " << i << std::endl;
+            }
+
+            targetModel->addPoint
+                (SparseTimeValueModel::Point(frame, value, label));
         }
 
     } else if (isOutput<FlexiNoteModel>(n) || isOutput<NoteModel>(n) || isOutput<RegionModel>(n)) { //GF: Added Note Model
@@ -913,11 +1005,6 @@
 void
 FeatureExtractionModelTransformer::setCompletion(int n, int completion)
 {
-    int binCount = 1;
-    if (m_descriptors[n]->hasFixedBinCount) {
-	binCount = m_descriptors[n]->binCount;
-    }
-
 //    SVDEBUG << "FeatureExtractionModelTransformer::setCompletion("
 //              << completion << ")" << endl;
 
--- a/transform/FeatureExtractionModelTransformer.h	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/FeatureExtractionModelTransformer.h	Tue Mar 11 17:30:35 2014 +0000
@@ -23,8 +23,10 @@
 #include <vamp-hostsdk/Plugin.h>
 
 #include <iostream>
+#include <map>
 
 class DenseTimeValueModel;
+class SparseTimeValueModel;
 
 class FeatureExtractionModelTransformer : public ModelTransformer
 {
@@ -42,6 +44,10 @@
 
     virtual ~FeatureExtractionModelTransformer();
 
+    // ModelTransformer method, retrieve the additional models
+    Models getAdditionalOutputModels();
+    bool willHaveAdditionalOutputModels();
+
 protected:
     bool initialise();
 
@@ -50,9 +56,14 @@
     Vamp::Plugin *m_plugin;
     std::vector<Vamp::Plugin::OutputDescriptor *> m_descriptors; // per transform
     std::vector<int> m_fixedRateFeatureNos; // to assign times to FixedSampleRate features
-    std::vector<int> m_outputNos;
+    std::vector<int> m_outputNos; // list of plugin output indexes required for this group of transforms
 
-    void createOutputModel(int n);
+    void createOutputModels(int n);
+
+    std::map<int, bool> m_needAdditionalModels; // transformNo -> necessity
+    typedef std::map<int, std::map<int, SparseTimeValueModel *> > AdditionalModelMap;
+    AdditionalModelMap m_additionalModels;
+    SparseTimeValueModel *getAdditionalModel(int transformNo, int binNo);
 
     void addFeature(int n,
                     size_t blockFrame,
--- a/transform/ModelTransformer.cpp	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/ModelTransformer.cpp	Tue Mar 11 17:30:35 2014 +0000
@@ -18,6 +18,7 @@
 ModelTransformer::ModelTransformer(Input input, const Transform &transform) :
     m_input(input),
     m_detached(false),
+    m_detachedAdd(false),
     m_abandoned(false)
 {
     m_transforms.push_back(transform);
@@ -27,6 +28,7 @@
     m_transforms(transforms),
     m_input(input),
     m_detached(false),
+    m_detachedAdd(false),
     m_abandoned(false)
 {
 }
@@ -36,9 +38,12 @@
     m_abandoned = true;
     wait();
     if (!m_detached) {
-        foreach (Model *m, m_outputs) {
-            delete m;
-        }
+        Models mine = getOutputModels();
+        foreach (Model *m, mine) delete m;
+    }
+    if (!m_detachedAdd) {
+        Models mine = getAdditionalOutputModels();
+        foreach (Model *m, mine) delete m;
     }
 }
 
--- a/transform/ModelTransformer.h	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/ModelTransformer.h	Tue Mar 11 17:30:35 2014 +0000
@@ -90,7 +90,35 @@
      * transformer so that they will not be deleted when the
      * transformer is.  The caller takes ownership of the models.
      */
-    Models detachOutputModels() { m_detached = true; return m_outputs; }
+    Models detachOutputModels() { 
+        m_detached = true; 
+        return getOutputModels(); 
+    }
+
+    /**
+     * Return any additional models that were created during
+     * processing. This might happen if, for example, a transform was
+     * configured to split a multi-bin output into separate single-bin
+     * models as it processed. These should not be queried until after
+     * the transform has completed.
+     */
+    virtual Models getAdditionalOutputModels() { return Models(); }
+
+    /**
+     * Return true if the current transform is one that may produce
+     * additional models (to be retrieved through
+     * getAdditionalOutputModels above).
+     */
+    virtual bool willHaveAdditionalOutputModels() { return false; }
+
+    /**
+     * Return the set of additional models, also detaching them from
+     * the transformer.  The caller takes ownership of the models.
+     */
+    virtual Models detachAdditionalOutputModels() { 
+        m_detachedAdd = true;
+        return getAdditionalOutputModels();
+    }
 
     /**
      * Return a warning or error message.  If getOutputModel returned
@@ -108,6 +136,7 @@
     Input m_input; // I don't own the model in this
     Models m_outputs; // I own this, unless...
     bool m_detached; // ... this is true.
+    bool m_detachedAdd;
     bool m_abandoned;
     QString m_message;
 };
--- a/transform/ModelTransformerFactory.cpp	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/ModelTransformerFactory.cpp	Tue Mar 11 17:30:35 2014 +0000
@@ -195,13 +195,14 @@
 Model *
 ModelTransformerFactory::transform(const Transform &transform,
                                    const ModelTransformer::Input &input,
-                                   QString &message) 
+                                   QString &message,
+                                   AdditionalModelHandler *handler) 
 {
     SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
 
     Transforms transforms;
     transforms.push_back(transform);
-    vector<Model *> mm = transformMultiple(transforms, input, message);
+    vector<Model *> mm = transformMultiple(transforms, input, message, handler);
     if (mm.empty()) return 0;
     else return mm[0];
 }
@@ -209,17 +210,22 @@
 vector<Model *>
 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
                                            const ModelTransformer::Input &input,
-                                           QString &message) 
+                                           QString &message,
+                                           AdditionalModelHandler *handler) 
 {
     SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
     
     ModelTransformer *t = createTransformer(transforms, input);
     if (!t) return vector<Model *>();
 
-    connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
+    if (handler) {
+        m_handlers[t] = handler;
+    }
 
     m_runningTransformers.insert(t);
 
+    connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
+
     t->start();
     vector<Model *> models = t->detachOutputModels();
 
@@ -270,6 +276,16 @@
 
     m_runningTransformers.erase(transformer);
 
+    if (m_handlers.find(transformer) != m_handlers.end()) {
+        if (transformer->willHaveAdditionalOutputModels()) {
+            vector<Model *> mm = transformer->detachAdditionalOutputModels();
+            m_handlers[transformer]->moreModelsAvailable(mm);
+        } else {
+            m_handlers[transformer]->noMoreModelsAvailable();
+        }
+        m_handlers.erase(transformer);
+    }
+
     transformer->wait(); // unnecessary but reassuring
     delete transformer;
 }
--- a/transform/ModelTransformerFactory.h	Tue Jan 28 15:01:54 2014 +0000
+++ b/transform/ModelTransformerFactory.h	Tue Mar 11 17:30:35 2014 +0000
@@ -70,6 +70,15 @@
                                  size_t startFrame = 0,
                                  size_t duration = 0,
                                  UserConfigurator *configurator = 0);
+
+    class AdditionalModelHandler {
+    public:
+        virtual ~AdditionalModelHandler() { }
+
+        // Exactly one of these functions will be called
+        virtual void moreModelsAvailable(std::vector<Model *> models) = 0;
+        virtual void noMoreModelsAvailable() = 0;
+    };
     
     /**
      * Return the output model resulting from applying the named
@@ -82,12 +91,21 @@
      * problem occurs, return 0.  Set message if there is any error or
      * warning to report.
      * 
+     * Some transforms may return additional models at the end of
+     * processing. (For example, a transform that splits an output
+     * into multiple one-per-bin models.) If an additionalModelHandler
+     * is provided here, its moreModelsAvailable method will be called
+     * when those models become available, and ownership of those
+     * models will be transferred to the handler. Otherwise (if the
+     * handler is null) any such models will be discarded.
+     *
      * The returned model is owned by the caller and must be deleted
      * when no longer needed.
      */
     Model *transform(const Transform &transform,
                      const ModelTransformer::Input &input,
-                     QString &message);
+                     QString &message,
+                     AdditionalModelHandler *handler = 0);
 
     /**
      * Return the multiple output models resulting from applying the
@@ -105,13 +123,22 @@
      * for the given transform, or if some other problem occurs,
      * return 0.  Set message if there is any error or warning to
      * report.
-     * 
+     *
+     * Some transforms may return additional models at the end of
+     * processing. (For example, a transform that splits an output
+     * into multiple one-per-bin models.) If an additionalModelHandler
+     * is provided here, its moreModelsAvailable method will be called
+     * when those models become available, and ownership of those
+     * models will be transferred to the handler. Otherwise (if the
+     * handler is null) any such models will be discarded.
+     *
      * The returned models are owned by the caller and must be deleted
      * when no longer needed.
      */
     std::vector<Model *> transformMultiple(const Transforms &transform,
                                            const ModelTransformer::Input &input,
-                                           QString &message);
+                                           QString &message,
+                                           AdditionalModelHandler *handler = 0);
 
 protected slots:
     void transformerFinished();
@@ -128,6 +155,9 @@
     typedef std::set<ModelTransformer *> TransformerSet;
     TransformerSet m_runningTransformers;
 
+    typedef std::map<ModelTransformer *, AdditionalModelHandler *> HandlerMap;
+    HandlerMap m_handlers;
+
     static ModelTransformerFactory *m_instance;
 };