svcore  1.9
ModelTransformerFactory.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008    
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "ModelTransformerFactory.h"
00017 
00018 #include "FeatureExtractionModelTransformer.h"
00019 #include "RealTimeEffectModelTransformer.h"
00020 
00021 #include "TransformFactory.h"
00022 
00023 #include "base/AudioPlaySource.h"
00024 
00025 #include "plugin/FeatureExtractionPluginFactory.h"
00026 #include "plugin/RealTimePluginFactory.h"
00027 #include "plugin/PluginXml.h"
00028 
00029 #include "data/model/DenseTimeValueModel.h"
00030 
00031 #include <vamp-hostsdk/PluginHostAdapter.h>
00032 
00033 #include <iostream>
00034 #include <set>
00035 
00036 #include <QRegExp>
00037 
00038 using std::vector;
00039 
00040 ModelTransformerFactory *
00041 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
00042 
00043 ModelTransformerFactory *
00044 ModelTransformerFactory::getInstance()
00045 {
00046     return m_instance;
00047 }
00048 
00049 ModelTransformerFactory::~ModelTransformerFactory()
00050 {
00051 }
00052 
00053 ModelTransformer::Input
00054 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
00055                                                       const std::vector<Model *> &candidateInputModels,
00056                                                       Model *defaultInputModel,
00057                                                       AudioPlaySource *source,
00058                                                       int startFrame,
00059                                                       int duration,
00060                                                       UserConfigurator *configurator)
00061 {
00062     ModelTransformer::Input input(0);
00063 
00064     if (candidateInputModels.empty()) return input;
00065 
00067     //from the dialog for when the candidate input model is changed,
00068     //as we'll need to reinitialise the channel settings in the dialog
00069     Model *inputModel = candidateInputModels[0];
00070     QStringList candidateModelNames;
00071     QString defaultModelName;
00072     QMap<QString, Model *> modelMap;
00073     for (int i = 0; i < (int)candidateInputModels.size(); ++i) {
00074         QString modelName = candidateInputModels[i]->objectName();
00075         QString origModelName = modelName;
00076         int dupcount = 1;
00077         while (modelMap.contains(modelName)) {
00078             modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
00079         }
00080         modelMap[modelName] = candidateInputModels[i];
00081         candidateModelNames.push_back(modelName);
00082         if (candidateInputModels[i] == defaultInputModel) {
00083             defaultModelName = modelName;
00084         }
00085     }
00086 
00087     QString id = transform.getPluginIdentifier();
00088     
00089     bool ok = true;
00090     QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
00091 
00092     cerr << "last configuration: " << configurationXml << endl;
00093 
00094     Vamp::PluginBase *plugin = 0;
00095 
00096     if (FeatureExtractionPluginFactory::instanceFor(id)) {
00097 
00098         cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl;
00099 
00100         Vamp::Plugin *vp =
00101             FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
00102             (id, inputModel->getSampleRate());
00103 
00104         plugin = vp;
00105 
00106     } else if (RealTimePluginFactory::instanceFor(id)) {
00107 
00108         RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
00109 
00110         int sampleRate = inputModel->getSampleRate();
00111         int blockSize = 1024;
00112         int channels = 1;
00113         if (source) {
00114             sampleRate = source->getTargetSampleRate();
00115             blockSize = source->getTargetBlockSize();
00116             channels = source->getTargetChannelCount();
00117         }
00118 
00119         RealTimePluginInstance *rtp = factory->instantiatePlugin
00120             (id, 0, 0, sampleRate, blockSize, channels);
00121 
00122         plugin = rtp;
00123     }
00124 
00125     if (plugin) {
00126 
00127         // Ensure block size etc are valid
00128         TransformFactory::getInstance()->
00129             makeContextConsistentWithPlugin(transform, plugin);
00130 
00131         // Prepare the plugin with any existing parameters already
00132         // found in the transform
00133         TransformFactory::getInstance()->
00134             setPluginParameters(transform, plugin);
00135         
00136         // For this interactive usage, we want to override those with
00137         // whatever the user chose last time around
00138         PluginXml(plugin).setParametersFromXml(configurationXml);
00139 
00140         if (configurator) {
00141             ok = configurator->configure(input, transform, plugin,
00142                                          inputModel, source,
00143                                          startFrame, duration,
00144                                          modelMap,
00145                                          candidateModelNames,
00146                                          defaultModelName);
00147         }
00148         
00149 
00150         TransformFactory::getInstance()->
00151             makeContextConsistentWithPlugin(transform, plugin);
00152 
00153         configurationXml = PluginXml(plugin).toXmlString();
00154 
00155         delete plugin;
00156     }
00157 
00158     if (ok) {
00159         m_lastConfigurations[transform.getIdentifier()] = configurationXml;
00160         input.setModel(inputModel);
00161     }
00162 
00163     return input;
00164 }
00165 
00166 ModelTransformer *
00167 ModelTransformerFactory::createTransformer(const Transforms &transforms,
00168                                            const ModelTransformer::Input &input)
00169 {
00170     ModelTransformer *transformer = 0;
00171 
00172     QString id = transforms[0].getPluginIdentifier();
00173 
00174     if (FeatureExtractionPluginFactory::instanceFor(id)) {
00175 
00176         transformer =
00177             new FeatureExtractionModelTransformer(input, transforms);
00178 
00179     } else if (RealTimePluginFactory::instanceFor(id)) {
00180 
00181         transformer =
00182             new RealTimeEffectModelTransformer(input, transforms[0]);
00183 
00184     } else {
00185         SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \""
00186                   << transforms[0].getIdentifier() << "\"" << endl;
00187         return transformer;
00188     }
00189 
00190     if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
00191     return transformer;
00192 }
00193 
00194 Model *
00195 ModelTransformerFactory::transform(const Transform &transform,
00196                                    const ModelTransformer::Input &input,
00197                                    QString &message,
00198                                    AdditionalModelHandler *handler) 
00199 {
00200     SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
00201 
00202     Transforms transforms;
00203     transforms.push_back(transform);
00204     vector<Model *> mm = transformMultiple(transforms, input, message, handler);
00205     if (mm.empty()) return 0;
00206     else return mm[0];
00207 }
00208 
00209 vector<Model *>
00210 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
00211                                            const ModelTransformer::Input &input,
00212                                            QString &message,
00213                                            AdditionalModelHandler *handler) 
00214 {
00215     SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
00216     
00217     ModelTransformer *t = createTransformer(transforms, input);
00218     if (!t) return vector<Model *>();
00219 
00220     if (handler) {
00221         m_handlers[t] = handler;
00222     }
00223 
00224     m_runningTransformers.insert(t);
00225 
00226     connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
00227 
00228     t->start();
00229     vector<Model *> models = t->detachOutputModels();
00230 
00231     if (!models.empty()) {
00232         QString imn = input.getModel()->objectName();
00233         QString trn =
00234             TransformFactory::getInstance()->getTransformFriendlyName
00235             (transforms[0].getIdentifier());
00236         for (int i = 0; i < (int)models.size(); ++i) {
00237             if (imn != "") {
00238                 if (trn != "") {
00239                     models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
00240                 } else {
00241                     models[i]->setObjectName(imn);
00242                 }
00243             } else if (trn != "") {
00244                 models[i]->setObjectName(trn);
00245             }
00246         }
00247     } else {
00248         t->wait();
00249     }
00250 
00251     message = t->getMessage();
00252 
00253     return models;
00254 }
00255 
00256 void
00257 ModelTransformerFactory::transformerFinished()
00258 {
00259     QObject *s = sender();
00260     ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
00261     
00262 //    SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
00263 
00264     if (!transformer) {
00265         cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
00266         return;
00267     }
00268 
00269     if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
00270         cerr << "WARNING: ModelTransformerFactory::transformerFinished(" 
00271                   << transformer
00272                   << "): I have no record of this transformer running!"
00273                   << endl;
00274     }
00275 
00276     m_runningTransformers.erase(transformer);
00277 
00278     if (m_handlers.find(transformer) != m_handlers.end()) {
00279         if (transformer->willHaveAdditionalOutputModels()) {
00280             vector<Model *> mm = transformer->detachAdditionalOutputModels();
00281             m_handlers[transformer]->moreModelsAvailable(mm);
00282         } else {
00283             m_handlers[transformer]->noMoreModelsAvailable();
00284         }
00285         m_handlers.erase(transformer);
00286     }
00287 
00288     transformer->wait(); // unnecessary but reassuring
00289     delete transformer;
00290 }
00291 
00292 void
00293 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
00294 {
00295     TransformerSet affected;
00296 
00297     for (TransformerSet::iterator i = m_runningTransformers.begin();
00298          i != m_runningTransformers.end(); ++i) {
00299 
00300         ModelTransformer *t = *i;
00301 
00302         if (t->getInputModel() == m) {
00303             affected.insert(t);
00304         } else {
00305             vector<Model *> mm = t->getOutputModels();
00306             for (int i = 0; i < (int)mm.size(); ++i) {
00307                 if (mm[i] == m) affected.insert(t);
00308             }
00309         }
00310     }
00311 
00312     for (TransformerSet::iterator i = affected.begin();
00313          i != affected.end(); ++i) {
00314 
00315         ModelTransformer *t = *i;
00316 
00317         t->abandon();
00318 
00319         t->wait(); // this should eventually call back on
00320                    // transformerFinished, which will remove from
00321                    // m_runningTransformers and delete.
00322     }
00323 }
00324