changeset 1740:fe3f7f8df3a3 by-id

More work on transformers
author Chris Cannam
date Wed, 26 Jun 2019 17:25:20 +0100
parents 565575463752
children 9d82b164f264
files transform/FeatureExtractionModelTransformer.cpp transform/FeatureExtractionModelTransformer.h transform/ModelTransformer.cpp transform/ModelTransformerFactory.cpp transform/ModelTransformerFactory.h transform/RealTimeEffectModelTransformer.cpp transform/RealTimeEffectModelTransformer.h
diffstat 7 files changed, 214 insertions(+), 314 deletions(-) [+]
line wrap: on
line diff
--- a/transform/FeatureExtractionModelTransformer.cpp	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/FeatureExtractionModelTransformer.cpp	Wed Jun 26 17:25:20 2019 +0100
@@ -650,7 +650,6 @@
 
     auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
     if (!input) {
-        SVCERR << "FeatureExtractionModelTransformer::run: Input model not (no longer?) available, abandoning" << endl;
         abandon();
         return;
     }
@@ -794,22 +793,22 @@
 
             if (m_abandoned) break;
 
-            Vamp::Plugin::FeatureSet features = m_plugin->process
+            auto features = m_plugin->process
                 (buffers,
                  RealTime::frame2RealTime(blockFrame, sampleRate)
                  .toVampRealTime());
             
             if (m_abandoned) break;
 
-            for (int j = 0; j < (int)m_outputNos.size(); ++j) {
-                for (int fi = 0; fi < (int)features[m_outputNos[j]].size(); ++fi) {
-                    Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi];
+            for (int j = 0; in_range_for(m_outputNos, j); ++j) {
+                for (int fi = 0; in_range_for(features[m_outputNos[j]], fi); ++fi) {
+                    auto feature = features[m_outputNos[j]][fi];
                     addFeature(j, blockFrame, feature);
                 }
             }
 
             if (blockFrame == contextStart || completion > prevCompletion) {
-                for (int j = 0; j < (int)m_outputNos.size(); ++j) {
+                for (int j = 0; in_range_for(m_outputNos, j); ++j) {
                     setCompletion(j, completion);
                 }
                 prevCompletion = completion;
@@ -820,11 +819,11 @@
         }
 
         if (!m_abandoned) {
-            Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures();
+            auto features = m_plugin->getRemainingFeatures();
 
-            for (int j = 0; j < (int)m_outputNos.size(); ++j) {
-                for (int fi = 0; fi < (int)features[m_outputNos[j]].size(); ++fi) {
-                    Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi];
+            for (int j = 0; in_range_for(m_outputNos, j); ++j) {
+                for (int fi = 0; in_range_for(features[m_outputNos[j]], fi); ++fi) {
+                    auto feature = features[m_outputNos[j]][fi];
                     addFeature(j, blockFrame, feature);
                 }
             }
@@ -990,129 +989,116 @@
     // to create.
 
     ModelId outputId = m_outputs[n];
-    bool found = false;
+
+    if (isOutputType<SparseOneDimensionalModel>(n)) {
+
+        auto model = ModelById::getAs<SparseOneDimensionalModel>(outputId);
+        if (!model) return;
+        model->add(Event(frame, feature.label.c_str()));
+        
+    } else if (isOutputType<SparseTimeValueModel>(n)) {
+
+        auto model = ModelById::getAs<SparseTimeValueModel>(outputId);
+        if (!model) return;
+
+        for (int i = 0; in_range_for(feature.values, i); ++i) {
+
+            float value = feature.values[i];
+
+            QString label = feature.label.c_str();
+            if (feature.values.size() > 1) {
+                label = QString("[%1] %2").arg(i+1).arg(label);
+            }
+
+            auto targetModel = model;
+
+            if (m_needAdditionalModels[n] && i > 0) {
+                targetModel = ModelById::getAs<SparseTimeValueModel>
+                    (getAdditionalModel(n, i));
+                if (!targetModel) targetModel = model;
+            }
+
+            targetModel->add(Event(frame, value, label));
+        }
+
+    } else if (isOutputType<NoteModel>(n) || isOutputType<RegionModel>(n)) {
     
-    if (!found) {
-        auto model = ModelById::getAs<SparseOneDimensionalModel>(outputId);
-        if (model) {
-            found = true;
-            model->add(Event(frame, feature.label.c_str()));
+        int index = 0;
+
+        float value = 0.0;
+        if ((int)feature.values.size() > index) {
+            value = feature.values[index++];
         }
-    }
-    
-    if (!found) {
-        auto model = ModelById::getAs<SparseTimeValueModel>(outputId);
-        if (model) {
-            found = true;
 
-            for (int i = 0; in_range_for(feature.values, i); ++i) {
-
-                float value = feature.values[i];
-
-                QString label = feature.label.c_str();
-                if (feature.values.size() > 1) {
-                    label = QString("[%1] %2").arg(i+1).arg(label);
-                }
-
-                auto targetModel = model;
-
-                if (m_needAdditionalModels[n] && i > 0) {
-                    targetModel = ModelById::getAs<SparseTimeValueModel>
-                        (getAdditionalModel(n, i));
-                    if (!targetModel) targetModel = model;
-                }
-
-                targetModel->add(Event(frame, value, label));
+        sv_frame_t duration = 1;
+        if (feature.hasDuration) {
+            duration = RealTime::realTime2Frame(feature.duration, inputRate);
+        } else {
+            if (in_range_for(feature.values, index)) {
+                duration = lrintf(feature.values[index++]);
             }
         }
-    }
-    
-    if (!found) {
-        if (ModelById::getAs<NoteModel>(outputId) ||
-            ModelById::getAs<RegionModel>(outputId)) {
-            found = true;
 
-            int index = 0;
+        auto noteModel = ModelById::getAs<NoteModel>(outputId);
+        if (noteModel) {
 
-            float value = 0.0;
+            float velocity = 100;
             if ((int)feature.values.size() > index) {
-                value = feature.values[index++];
+                velocity = feature.values[index++];
             }
+            if (velocity < 0) velocity = 127;
+            if (velocity > 127) velocity = 127;
+            
+            noteModel->add(Event(frame, value, // value is pitch
+                                 duration,
+                                 velocity / 127.f,
+                                 feature.label.c_str()));
+        }
 
-            sv_frame_t duration = 1;
-            if (feature.hasDuration) {
-                duration = RealTime::realTime2Frame(feature.duration, inputRate);
-            } else {
-                if (in_range_for(feature.values, index)) {
-                    duration = lrintf(feature.values[index++]);
-                }
-            }
-
-            auto noteModel = ModelById::getAs<NoteModel>(outputId);
-            if (noteModel) {
-
-                float velocity = 100;
-                if ((int)feature.values.size() > index) {
-                    velocity = feature.values[index++];
-                }
-                if (velocity < 0) velocity = 127;
-                if (velocity > 127) velocity = 127;
-
-                noteModel->add(Event(frame, value, // value is pitch
-                                     duration,
-                                     velocity / 127.f,
-                                     feature.label.c_str()));
-            }
-
-            auto regionModel = ModelById::getAs<RegionModel>(outputId);
-            if (regionModel) {
-
-                if (feature.hasDuration && !feature.values.empty()) {
-
-                    for (int i = 0; in_range_for(feature.values, i); ++i) {
-
-                        float value = feature.values[i];
-
-                        QString label = feature.label.c_str();
-                        if (feature.values.size() > 1) {
-                            label = QString("[%1] %2").arg(i+1).arg(label);
-                        }
-
-                        regionModel->add(Event(frame,
-                                               value,
-                                               duration,
-                                               label));
+        auto regionModel = ModelById::getAs<RegionModel>(outputId);
+        if (regionModel) {
+            
+            if (feature.hasDuration && !feature.values.empty()) {
+                
+                for (int i = 0; in_range_for(feature.values, i); ++i) {
+                    
+                    float value = feature.values[i];
+                    
+                    QString label = feature.label.c_str();
+                    if (feature.values.size() > 1) {
+                        label = QString("[%1] %2").arg(i+1).arg(label);
                     }
-                } else {
-            
+                    
                     regionModel->add(Event(frame,
                                            value,
                                            duration,
-                                           feature.label.c_str()));
+                                           label));
                 }
+            } else {
+                
+                regionModel->add(Event(frame,
+                                       value,
+                                       duration,
+                                       feature.label.c_str()));
             }
         }
+
+    } else if (isOutputType<EditableDenseThreeDimensionalModel>(n)) {
+
+        auto model = ModelById::getAs
+            <EditableDenseThreeDimensionalModel>(outputId);
+        if (!model) return;
+        
+        DenseThreeDimensionalModel::Column values = feature.values;
+        
+        if (!feature.hasTimestamp && m_fixedRateFeatureNos[n] >= 0) {
+            model->setColumn(m_fixedRateFeatureNos[n], values);
+        } else {
+            model->setColumn(int(frame / model->getResolution()), values);
+        }
     }
 
-    if (!found) {
-        auto model = ModelById::getAs
-            <EditableDenseThreeDimensionalModel>(outputId);
-        if (model) {
-            found = true;
-        
-            DenseThreeDimensionalModel::Column values = feature.values;
-        
-            if (!feature.hasTimestamp && m_fixedRateFeatureNos[n] >= 0) {
-                model->setColumn(m_fixedRateFeatureNos[n], values);
-            } else {
-                model->setColumn(int(frame / model->getResolution()), values);
-            }
-        }
-    }
-
-    if (!found) {
-        SVDEBUG << "FeatureExtractionModelTransformer::addFeature: Unknown output model type!" << endl;
-    }
+    SVDEBUG << "FeatureExtractionModelTransformer::addFeature: Unknown output model type!" << endl;
 }
 
 void
@@ -1123,47 +1109,11 @@
               << completion << ")" << endl;
 #endif
 
-    ModelId outputId = m_outputs[n];
-    bool found = false;
-    
-    if (!found) {
-        auto model = ModelById::getAs<SparseOneDimensionalModel>(outputId);
-        if (model) {
-            found = true;
-            model->setCompletion(completion, true);
-        }
-    }
-
-    if (!found) {
-        auto model = ModelById::getAs<SparseTimeValueModel>(outputId);
-        if (model) {
-            found = true;
-            model->setCompletion(completion, true);
-        }
-    }
-
-    if (!found) {
-        auto model = ModelById::getAs<NoteModel>(outputId);
-        if (model) {
-            found = true;
-            model->setCompletion(completion, true);
-        }
-    }
-
-    if (!found) {
-        auto model = ModelById::getAs<RegionModel>(outputId);
-        if (model) {
-            found = true;
-            model->setCompletion(completion, true);
-        }
-    }
-
-    if (!found) {
-        auto model = ModelById::getAs<EditableDenseThreeDimensionalModel>(outputId);
-        if (model) {
-            found = true;
-            model->setCompletion(completion, true);
-        }
-    }
+    (void)
+        (setOutputCompletion<SparseOneDimensionalModel>(n, completion) ||
+         setOutputCompletion<SparseTimeValueModel>(n, completion) ||
+         setOutputCompletion<NoteModel>(n, completion) ||
+         setOutputCompletion<RegionModel>(n, completion) ||
+         setOutputCompletion<EditableDenseThreeDimensionalModel>(n, completion));
 }
 
--- a/transform/FeatureExtractionModelTransformer.h	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/FeatureExtractionModelTransformer.h	Wed Jun 26 17:25:20 2019 +0100
@@ -95,27 +95,23 @@
     QWaitCondition m_outputsCondition;
     void awaitOutputModels() override;
     
-    // just casts:
-/*!!!
-    DenseTimeValueModel *getConformingInput();
-
-    template <typename ModelClass> bool isOutput(int n) {
-        return dynamic_cast<ModelClass *>(m_outputs[n]) != 0;
+    template <typename T> bool isOutputType(int n) {
+        if (!ModelById::getAs<T>(m_outputs[n])) {
+            return false;
+        } else {
+            return true;
+        }
     }
 
-    template <typename ModelClass> ModelClass *getConformingOutput(int n) {
-        if ((int)m_outputs.size() > n) {
-            ModelClass *mc = dynamic_cast<ModelClass *>(m_outputs[n]);
-            if (!mc) {
-                std::cerr << "FeatureExtractionModelTransformer::getOutput: Output model not conformable" << std::endl;
-            }
-            return mc;
+    template <typename T> bool setOutputCompletion(int n, int completion) {
+        auto model = ModelById::getAs<T>(m_outputs[n]);
+        if (!model) {
+            return false;
         } else {
-            std::cerr << "FeatureExtractionModelTransformer::getOutput: No such output number " << n << std::endl;
-            return 0;
+            model->setCompletion(completion, true);
+            return true;
         }
     }
-*/
 };
 
 #endif
--- a/transform/ModelTransformer.cpp	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/ModelTransformer.cpp	Wed Jun 26 17:25:20 2019 +0100
@@ -17,8 +17,6 @@
 
 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,8 +25,6 @@
 ModelTransformer::ModelTransformer(Input input, const Transforms &transforms) :
     m_transforms(transforms),
     m_input(input),
-    m_detached(false),
-    m_detachedAdd(false),
     m_abandoned(false)
 {
 }
@@ -37,13 +33,5 @@
 {
     m_abandoned = true;
     wait();
-    if (!m_detached) {
-        Models mine = getOutputModels();
-        foreach (Model *m, mine) delete m;
-    }
-    if (!m_detachedAdd) {
-        Models mine = getAdditionalOutputModels();
-        foreach (Model *m, mine) delete m;
-    }
 }
 
--- a/transform/ModelTransformerFactory.cpp	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/ModelTransformerFactory.cpp	Wed Jun 26 17:25:20 2019 +0100
@@ -56,8 +56,8 @@
 
 ModelTransformer::Input
 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
-                                                      const vector<Model *> &candidateInputModels,
-                                                      Model *defaultInputModel,
+                                                      vector<ModelId> candidateInputModels,
+                                                      ModelId defaultInputModel,
                                                       AudioPlaySource *source,
                                                       sv_frame_t startFrame,
                                                       sv_frame_t duration,
@@ -65,26 +65,39 @@
 {
     QMutexLocker locker(&m_mutex);
     
-    ModelTransformer::Input input(nullptr);
+    ModelTransformer::Input input({});
 
     if (candidateInputModels.empty()) return input;
 
     //!!! This will need revision -- we'll have to have a callback
     //from the dialog for when the candidate input model is changed,
     //as we'll need to reinitialise the channel settings in the dialog
-    Model *inputModel = candidateInputModels[0];
+    ModelId inputModel = candidateInputModels[0];
     QStringList candidateModelNames;
     QString defaultModelName;
-    QMap<QString, Model *> modelMap;
-    for (int i = 0; i < (int)candidateInputModels.size(); ++i) {
-        QString modelName = candidateInputModels[i]->objectName();
+    QMap<QString, ModelId> modelMap;
+
+    sv_samplerate_t defaultSampleRate;
+    {   auto im = ModelById::get(inputModel);
+        if (!im) return input;
+        defaultSampleRate = im->getSampleRate();
+    }
+    
+    for (int i = 0; in_range_for(candidateInputModels, i); ++i) {
+
+        auto model = ModelById::get(candidateInputModels[i]);
+        if (!model) return input;
+        
+        QString modelName = model->objectName();
         QString origModelName = modelName;
         int dupcount = 1;
         while (modelMap.contains(modelName)) {
             modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
         }
+        
         modelMap[modelName] = candidateInputModels[i];
         candidateModelNames.push_back(modelName);
+        
         if (candidateInputModels[i] == defaultInputModel) {
             defaultModelName = modelName;
         }
@@ -105,7 +118,7 @@
         
         RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
 
-        sv_samplerate_t sampleRate = inputModel->getSampleRate();
+        sv_samplerate_t sampleRate = defaultSampleRate;
         int blockSize = 1024;
         int channels = 1;
         if (source) {
@@ -125,7 +138,7 @@
 
         Vamp::Plugin *vp =
             FeatureExtractionPluginFactory::instance()->instantiatePlugin
-            (id, float(inputModel->getSampleRate()));
+            (id, float(defaultSampleRate));
 
         plugin = vp;
     }
@@ -196,7 +209,7 @@
     return transformer;
 }
 
-Model *
+ModelId
 ModelTransformerFactory::transform(const Transform &transform,
                                    const ModelTransformer::Input &input,
                                    QString &message,
@@ -206,12 +219,12 @@
 
     Transforms transforms;
     transforms.push_back(transform);
-    vector<Model *> mm = transformMultiple(transforms, input, message, handler);
-    if (mm.empty()) return nullptr;
+    vector<ModelId> mm = transformMultiple(transforms, input, message, handler);
+    if (mm.empty()) return {};
     else return mm[0];
 }
 
-vector<Model *>
+vector<ModelId>
 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
                                            const ModelTransformer::Input &input,
                                            QString &message,
@@ -220,9 +233,12 @@
     SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
     
     QMutexLocker locker(&m_mutex);
+
+    auto inputModel = ModelById::get(input.getModel());
+    if (!inputModel) return {};
     
     ModelTransformer *t = createTransformer(transforms, input);
-    if (!t) return vector<Model *>();
+    if (!t) return {};
 
     if (handler) {
         m_handlers[t] = handler;
@@ -233,22 +249,24 @@
     connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
 
     t->start();
-    vector<Model *> models = t->detachOutputModels();
-
+    vector<ModelId> models = t->getOutputModels();
+    
     if (!models.empty()) {
-        QString imn = input.getModel()->objectName();
+        QString imn = inputModel->objectName();
         QString trn =
             TransformFactory::getInstance()->getTransformFriendlyName
             (transforms[0].getIdentifier());
-        for (int i = 0; i < (int)models.size(); ++i) {
+        for (int i = 0; in_range_for(models, i); ++i) {
+            auto model = ModelById::get(models[i]);
+            if (!model) continue;
             if (imn != "") {
                 if (trn != "") {
-                    models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
+                    model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
                 } else {
-                    models[i]->setObjectName(imn);
+                    model->setObjectName(imn);
                 }
             } else if (trn != "") {
-                models[i]->setObjectName(trn);
+                model->setObjectName(trn);
             }
         }
     } else {
@@ -284,12 +302,12 @@
 
     m_runningTransformers.erase(transformer);
 
-    map<AdditionalModelHandler *, vector<Model *>> toNotifyOfMore;
+    map<AdditionalModelHandler *, vector<ModelId>> toNotifyOfMore;
     vector<AdditionalModelHandler *> toNotifyOfNoMore;
     
     if (m_handlers.find(transformer) != m_handlers.end()) {
         if (transformer->willHaveAdditionalOutputModels()) {
-            vector<Model *> mm = transformer->detachAdditionalOutputModels();
+            vector<ModelId> mm = transformer->getAdditionalOutputModels();
             toNotifyOfMore[m_handlers[transformer]] = mm;
         } else {
             toNotifyOfNoMore.push_back(m_handlers[transformer]);
@@ -299,11 +317,9 @@
 
     m_mutex.unlock();
 
-    // These calls have to be made without the mutex held, as they may
-    // ultimately call back on us (e.g. we have one baroque situation
-    // where this could trigger a command to create a layer, which
-    // triggers the command history to clip the stack, which deletes a
-    // spare old model, which calls back on our modelAboutToBeDeleted)
+    // We make these calls without the mutex held, in case they
+    // ultimately call back on us - not such a concern as in the old
+    // model lifecycle but just in case
     
     for (const auto &i: toNotifyOfMore) {
         i.first->moreModelsAvailable(i.second);
@@ -322,43 +338,6 @@
     delete transformer;
 }
 
-void
-ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
-{
-    TransformerSet affected;
-
-    {
-        QMutexLocker locker(&m_mutex);
-    
-        for (TransformerSet::iterator i = m_runningTransformers.begin();
-             i != m_runningTransformers.end(); ++i) {
-
-            ModelTransformer *t = *i;
-
-            if (t->getInputModel() == m) {
-                affected.insert(t);
-            } else {
-                vector<Model *> mm = t->getOutputModels();
-                for (int i = 0; i < (int)mm.size(); ++i) {
-                    if (mm[i] == m) affected.insert(t);
-                }
-            }
-        }
-    }
-
-    for (TransformerSet::iterator i = affected.begin();
-         i != affected.end(); ++i) {
-
-        ModelTransformer *t = *i;
-
-        t->abandon();
-
-        t->wait(); // this should eventually call back on
-                   // transformerFinished, which will remove from
-                   // m_runningTransformers and delete.
-    }
-}
-
 bool
 ModelTransformerFactory::haveRunningTransformers() const
 {
--- a/transform/ModelTransformerFactory.h	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/ModelTransformerFactory.h	Wed Jun 26 17:25:20 2019 +0100
@@ -46,11 +46,11 @@
         virtual bool configure(ModelTransformer::Input &input,
                                Transform &transform,
                                Vamp::PluginBase *plugin,
-                               Model *&inputModel,
+                               ModelId &inputModel,
                                AudioPlaySource *source,
                                sv_frame_t startFrame,
                                sv_frame_t duration,
-                               const QMap<QString, Model *> &modelMap,
+                               const QMap<QString, ModelId> &modelMap,
                                QStringList candidateModelNames,
                                QString defaultModelName) = 0;
     };
@@ -59,14 +59,14 @@
      * Fill out the configuration for the given transform (may include
      * asking the user by calling back on the UserConfigurator).
      * Returns the selected input model and channel if the transform
-     * is acceptable, or an input with a null model if the operation
+     * is acceptable, or an input with no model if the operation
      * should be cancelled.  Audio play source may be used to audition
      * effects plugins, if provided.
      */
     ModelTransformer::Input
     getConfigurationForTransform(Transform &transform,
-                                 const std::vector<Model *> &candidateInputModels,
-                                 Model *defaultInputModel,
+                                 std::vector<ModelId> candidateInputModels,
+                                 ModelId defaultInputModel,
                                  AudioPlaySource *source = 0,
                                  sv_frame_t startFrame = 0,
                                  sv_frame_t duration = 0,
@@ -77,7 +77,7 @@
         virtual ~AdditionalModelHandler() { }
 
         // Exactly one of these functions will be called
-        virtual void moreModelsAvailable(std::vector<Model *> models) = 0;
+        virtual void moreModelsAvailable(std::vector<ModelId> models) = 0;
         virtual void noMoreModelsAvailable() = 0;
     };
     
@@ -104,10 +104,10 @@
      * 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,
-                     AdditionalModelHandler *handler = 0);
+    ModelId transform(const Transform &transform,
+                      const ModelTransformer::Input &input,
+                      QString &message,
+                      AdditionalModelHandler *handler = 0);
 
     /**
      * Return the multiple output models resulting from applying the
@@ -141,7 +141,7 @@
      * The returned models are owned by the caller and must be deleted
      * when no longer needed.
      */
-    std::vector<Model *> transformMultiple(const Transforms &transform,
+    std::vector<ModelId> transformMultiple(const Transforms &transform,
                                            const ModelTransformer::Input &input,
                                            QString &message,
                                            AdditionalModelHandler *handler = 0);
@@ -154,8 +154,6 @@
 protected slots:
     void transformerFinished();
 
-    void modelAboutToBeDeleted(Model *);
-
 protected:
     ModelTransformer *createTransformer(const Transforms &transforms,
                                         const ModelTransformer::Input &input);
--- a/transform/RealTimeEffectModelTransformer.cpp	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/RealTimeEffectModelTransformer.cpp	Wed Jun 26 17:25:20 2019 +0100
@@ -58,8 +58,11 @@
         return;
     }
 
-    DenseTimeValueModel *input = getConformingInput();
-    if (!input) return;
+    auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
+    if (!input) {
+        SVCERR << "RealTimeEffectModelTransformer: Input is absent or of wrong type" << endl;
+        return;
+    }
 
     m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
                                           input->getSampleRate(),
@@ -87,19 +90,21 @@
             outputChannels = input->getChannelCount();
         }
 
-        WritableWaveFileModel *model = new WritableWaveFileModel
+        auto model = std::make_shared<WritableWaveFileModel>
             (input->getSampleRate(), outputChannels);
 
-        m_outputs.push_back(model);
+        ModelById::add(model);
+        m_outputs.push_back(model->getId());
 
     } else {
         
-        SparseTimeValueModel *model = new SparseTimeValueModel
-            (input->getSampleRate(), transform.getBlockSize(), 0.0, 0.0, false);
-
+        auto model = std::make_shared<SparseTimeValueModel>
+            (input->getSampleRate(), transform.getBlockSize(),
+             0.0, 0.0, false);
         if (m_units != "") model->setScaleUnits(m_units);
 
-        m_outputs.push_back(model);
+        ModelById::add(model);
+        m_outputs.push_back(model->getId());
     }
 }
 
@@ -108,38 +113,39 @@
     delete m_plugin;
 }
 
-DenseTimeValueModel *
-RealTimeEffectModelTransformer::getConformingInput()
-{
-    DenseTimeValueModel *dtvm =
-        dynamic_cast<DenseTimeValueModel *>(getInputModel());
-    if (!dtvm) {
-        SVDEBUG << "RealTimeEffectModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << endl;
-    }
-    return dtvm;
-}
-
 void
 RealTimeEffectModelTransformer::run()
 {
-    DenseTimeValueModel *input = getConformingInput();
-    if (!input) return;
-
-    while (!input->isReady() && !m_abandoned) {
-        SVDEBUG << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << endl;
-        usleep(500000);
-    }
-    if (m_abandoned) {
+    if (m_outputs.empty()) {
+        abandon();
         return;
     }
-    if (m_outputs.empty()) {
+
+    bool ready = false;
+    while (!ready && !m_abandoned) {
+        { // scope so as to release input shared_ptr before sleeping
+            auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
+            if (!input) {
+                abandon();
+                return;
+            }
+            ready = input->isReady();
+        }
+        if (!ready) {
+            SVDEBUG << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << endl;
+            usleep(500000);
+        }
+    }
+    if (m_abandoned) return;
+
+    auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
+    if (!input) {
+        abandon();
         return;
     }
-    
-    SparseTimeValueModel *stvm =
-        dynamic_cast<SparseTimeValueModel *>(m_outputs[0]);
-    WritableWaveFileModel *wwfm =
-        dynamic_cast<WritableWaveFileModel *>(m_outputs[0]);
+
+    auto stvm = ModelById::getAs<SparseTimeValueModel>(m_outputs[0]);
+    auto wwfm = ModelById::getAs<WritableWaveFileModel>(m_outputs[0]);
 
     if (!stvm && !wwfm) {
         return;
@@ -157,8 +163,8 @@
 
     float **inbufs = m_plugin->getAudioInputBuffers();
 
-    sv_frame_t startFrame = m_input.getModel()->getStartFrame();
-    sv_frame_t endFrame = m_input.getModel()->getEndFrame();
+    sv_frame_t startFrame = input->getStartFrame();
+    sv_frame_t endFrame = input->getEndFrame();
 
     Transform transform = m_transforms[0];
     
@@ -242,20 +248,6 @@
             }
         }
 
-/*
-        cerr << "Input for plugin: " << m_plugin->getAudioInputCount() << " channels "<< endl;
-
-        for (int ch = 0; ch < m_plugin->getAudioInputCount(); ++ch) {
-            cerr << "Input channel " << ch << endl;
-            for (int i = 0; i < 100; ++i) {
-                cerr << inbufs[ch][i] << " ";
-                if (isnan(inbufs[ch][i])) {
-                    cerr << "\n\nWARNING: NaN in audio input" << endl;
-                }
-            }
-        }
-*/
-
         m_plugin->run(RealTime::frame2RealTime(blockFrame, sampleRate));
 
         if (stvm) {
--- a/transform/RealTimeEffectModelTransformer.h	Wed Jun 26 14:59:09 2019 +0100
+++ b/transform/RealTimeEffectModelTransformer.h	Wed Jun 26 17:25:20 2019 +0100
@@ -36,9 +36,6 @@
     QString m_units;
     RealTimePluginInstance *m_plugin;
     int m_outputNo;
-
-    // just casts
-    DenseTimeValueModel *getConformingInput();
 };
 
 #endif