changeset 876:47aa3aeb687b tonioni

For outputs with unknown bin count or multiple bins with variable sample rate, create additional output models for bins beyond the first
author Chris Cannam
date Wed, 29 Jan 2014 09:31:22 +0000
parents 3e6ed8a8577b
children b109b88bfa85
files transform/FeatureExtractionModelTransformer.cpp transform/FeatureExtractionModelTransformer.h transform/ModelTransformer.cpp transform/ModelTransformer.h
diffstat 4 files changed, 122 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/transform/FeatureExtractionModelTransformer.cpp	Tue Jan 28 18:52:22 2014 +0000
+++ b/transform/FeatureExtractionModelTransformer.cpp	Wed Jan 29 09:31:22 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;
 
@@ -392,7 +395,7 @@
         QString outputEventTypeURI = description.getOutputEventTypeURI(outputId);
         out->setRDFTypeURI(outputEventTypeURI);
 
-    } else if ((binCount == 1 && m_descriptors[n]->hasFixedBinCount) ||
+    } else if (binCount == 1 ||
                (m_descriptors[n]->sampleType == 
                 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) {
 
@@ -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 just 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,57 @@
     }
 }
 
+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;
+}
+
+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()
 {
@@ -799,7 +870,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
@@ -898,11 +979,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 18:52:22 2014 +0000
+++ b/transform/FeatureExtractionModelTransformer.h	Wed Jan 29 09:31:22 2014 +0000
@@ -23,8 +23,10 @@
 #include <vamp-hostsdk/Plugin.h>
 
 #include <iostream>
+#include <map>
 
 class DenseTimeValueModel;
+class SparseTimeValueModel;
 
 class FeatureExtractionModelTransformer : public ModelTransformer
 {
@@ -50,9 +52,17 @@
     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);
+
+    // ModelTransformer method, retrieve the additional models
+    Models getAdditionalOutputModels();
 
     void addFeature(int n,
                     size_t blockFrame,
--- a/transform/ModelTransformer.cpp	Tue Jan 28 18:52:22 2014 +0000
+++ b/transform/ModelTransformer.cpp	Wed Jan 29 09:31:22 2014 +0000
@@ -36,9 +36,19 @@
     m_abandoned = true;
     wait();
     if (!m_detached) {
-        foreach (Model *m, m_outputs) {
+        Models mine = getOutputModels(); // including any additional ones
+        foreach (Model *m, mine) {
             delete m;
         }
     }
 }
 
+ModelTransformer::Models
+ModelTransformer::getOutputModels()
+{
+    Models out(m_outputs);
+    Models add(getAdditionalOutputModels());
+    foreach (Model *m, add) out.push_back(m);
+    return out;
+}
+
--- a/transform/ModelTransformer.h	Tue Jan 28 18:52:22 2014 +0000
+++ b/transform/ModelTransformer.h	Wed Jan 29 09:31:22 2014 +0000
@@ -83,14 +83,14 @@
      * be initialised; an error message may be available via
      * getMessage() in this situation.
      */
-    Models getOutputModels() { return m_outputs; }
+    Models getOutputModels();        
 
     /**
      * Return the set of output models, also detaching them from the
      * 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 a warning or error message.  If getOutputModel returned
@@ -104,6 +104,14 @@
     ModelTransformer(Input input, const Transform &transform);
     ModelTransformer(Input input, const Transforms &transforms);
 
+    /**
+     * 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.
+     */
+    virtual Models getAdditionalOutputModels() { return Models(); }
+
     Transforms m_transforms;
     Input m_input; // I don't own the model in this
     Models m_outputs; // I own this, unless...