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 "plugin/FeatureExtractionPluginFactory.h"
00024 #include "plugin/RealTimePluginFactory.h"
00025 #include "plugin/PluginXml.h"
00026 
00027 #include "widgets/PluginParameterDialog.h"
00028 
00029 #include "data/model/DenseTimeValueModel.h"
00030 
00031 #include "vamp-sdk/PluginHostAdapter.h"
00032 
00033 #include "audioio/AudioCallbackPlaySource.h" 
00034 
00035 #include <iostream>
00036 #include <set>
00037 
00038 #include <QRegExp>
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 bool
00054 ModelTransformerFactory::getChannelRange(TransformId identifier,
00055                                          Vamp::PluginBase *plugin,
00056                                          int &minChannels, int &maxChannels)
00057 {
00058     Vamp::Plugin *vp = 0;
00059     if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) ||
00060         (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) {
00061         minChannels = vp->getMinChannelCount();
00062         maxChannels = vp->getMaxChannelCount();
00063         return true;
00064     } else {
00065         return TransformFactory::getInstance()->
00066             getTransformChannelRange(identifier, minChannels, maxChannels);
00067     }
00068 }
00069 
00070 ModelTransformer::Input
00071 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
00072                                                       const std::vector<Model *> &candidateInputModels,
00073                                                       Model *defaultInputModel,
00074                                                       AudioCallbackPlaySource *source,
00075                                                       size_t startFrame,
00076                                                       size_t duration)
00077 {
00078     ModelTransformer::Input input(0);
00079 
00080     if (candidateInputModels.empty()) return input;
00081 
00083     //from the dialog for when the candidate input model is changed,
00084     //as we'll need to reinitialise the channel settings in the dialog
00085     Model *inputModel = candidateInputModels[0];
00086     QStringList candidateModelNames;
00087     QString defaultModelName;
00088     std::map<QString, Model *> modelMap;
00089     for (size_t i = 0; i < candidateInputModels.size(); ++i) {
00090         QString modelName = candidateInputModels[i]->objectName();
00091         QString origModelName = modelName;
00092         int dupcount = 1;
00093         while (modelMap.find(modelName) != modelMap.end()) {
00094             modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
00095         }
00096         modelMap[modelName] = candidateInputModels[i];
00097         candidateModelNames.push_back(modelName);
00098         if (candidateInputModels[i] == defaultInputModel) {
00099             defaultModelName = modelName;
00100         }
00101     }
00102 
00103     QString id = transform.getPluginIdentifier();
00104     QString output = transform.getOutput();
00105     QString outputLabel = "";
00106     QString outputDescription = "";
00107     
00108     bool ok = false;
00109     QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
00110 
00111     std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
00112 
00113     Vamp::PluginBase *plugin = 0;
00114 
00115     bool frequency = false;
00116     bool effect = false;
00117     bool generator = false;
00118 
00119     if (FeatureExtractionPluginFactory::instanceFor(id)) {
00120 
00121         std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl;
00122 
00123         Vamp::Plugin *vp =
00124             FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
00125             (id, inputModel->getSampleRate());
00126 
00127         if (vp) {
00128 
00129             plugin = vp;
00130             frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
00131 
00132             std::vector<Vamp::Plugin::OutputDescriptor> od =
00133                 vp->getOutputDescriptors();
00134             if (od.size() > 1) {
00135                 for (size_t i = 0; i < od.size(); ++i) {
00136                     if (od[i].identifier == output.toStdString()) {
00137                         outputLabel = od[i].name.c_str();
00138                         outputDescription = od[i].description.c_str();
00139                         break;
00140                     }
00141                 }
00142             }
00143         }
00144 
00145     } else if (RealTimePluginFactory::instanceFor(id)) {
00146 
00147         RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
00148         const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
00149 
00150         if (desc->audioInputPortCount > 0 && 
00151             desc->audioOutputPortCount > 0 &&
00152             !desc->isSynth) {
00153             effect = true;
00154         }
00155 
00156         if (desc->audioInputPortCount == 0) {
00157             generator = true;
00158         }
00159 
00160         if (output != "A") {
00161             int outputNo = output.toInt();
00162             if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) {
00163                 outputLabel = desc->controlOutputPortNames[outputNo].c_str();
00164             }
00165         }
00166 
00167         size_t sampleRate = inputModel->getSampleRate();
00168         size_t blockSize = 1024;
00169         size_t channels = 1;
00170         if (effect && source) {
00171             sampleRate = source->getTargetSampleRate();
00172             blockSize = source->getTargetBlockSize();
00173             channels = source->getTargetChannelCount();
00174         }
00175 
00176         RealTimePluginInstance *rtp = factory->instantiatePlugin
00177             (id, 0, 0, sampleRate, blockSize, channels);
00178 
00179         plugin = rtp;
00180 
00181         if (effect && source && rtp) {
00182             source->setAuditioningPlugin(rtp);
00183         }
00184     }
00185 
00186     if (plugin) {
00187 
00188         // Ensure block size etc are valid
00189         TransformFactory::getInstance()->
00190             makeContextConsistentWithPlugin(transform, plugin);
00191 
00192         // Prepare the plugin with any existing parameters already
00193         // found in the transform
00194         TransformFactory::getInstance()->
00195             setPluginParameters(transform, plugin);
00196         
00197         // For this interactive usage, we want to override those with
00198         // whatever the user chose last time around
00199         PluginXml(plugin).setParametersFromXml(configurationXml);
00200 
00201         int sourceChannels = 1;
00202         if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
00203             sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
00204                 ->getChannelCount();
00205         }
00206 
00207         int minChannels = 1, maxChannels = sourceChannels;
00208         getChannelRange(transform.getIdentifier(), plugin,
00209                         minChannels, maxChannels);
00210 
00211         int targetChannels = sourceChannels;
00212         if (!effect) {
00213             if (sourceChannels < minChannels) targetChannels = minChannels;
00214             if (sourceChannels > maxChannels) targetChannels = maxChannels;
00215         }
00216 
00217         int defaultChannel = -1; 
00218 
00219         PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
00220 
00221         if (candidateModelNames.size() > 1 && !generator) {
00222             dialog->setCandidateInputModels(candidateModelNames,
00223                                             defaultModelName);
00224         }
00225 
00226         if (startFrame != 0 || duration != 0) {
00227             dialog->setShowSelectionOnlyOption(true);
00228         }
00229 
00230         if (targetChannels > 0) {
00231             dialog->setChannelArrangement(sourceChannels, targetChannels,
00232                                           defaultChannel);
00233         }
00234         
00235         dialog->setOutputLabel(outputLabel, outputDescription);
00236         
00237         dialog->setShowProcessingOptions(true, frequency);
00238 
00239         if (dialog->exec() == QDialog::Accepted) {
00240             ok = true;
00241         }
00242 
00243         QString selectedInput = dialog->getInputModel();
00244         if (selectedInput != "") {
00245             if (modelMap.find(selectedInput) != modelMap.end()) {
00246                 inputModel = modelMap[selectedInput];
00247                 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl;
00248             } else {
00249                 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl;
00250             }
00251         } else {
00252             std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl;
00253         }
00254         
00255         // Write parameters back to transform object
00256         TransformFactory::getInstance()->
00257             setParametersFromPlugin(transform, plugin);
00258 
00259         input.setChannel(dialog->getChannel());
00260         
00262         //objects and input objects and stuff rather than passing
00263         //around all this misc stuff, but that's for tomorrow
00264         //(whenever that may be)
00265 
00266         if (startFrame != 0 || duration != 0) {
00267             if (dialog->getSelectionOnly()) {
00268                 transform.setStartTime(RealTime::frame2RealTime
00269                                        (startFrame, inputModel->getSampleRate()));
00270                 transform.setDuration(RealTime::frame2RealTime
00271                                       (duration, inputModel->getSampleRate()));
00272             }
00273         }
00274 
00275         size_t stepSize = 0, blockSize = 0;
00276         WindowType windowType = HanningWindow;
00277 
00278         dialog->getProcessingParameters(stepSize,
00279                                         blockSize,
00280                                         windowType);
00281 
00282         transform.setStepSize(stepSize);
00283         transform.setBlockSize(blockSize);
00284         transform.setWindowType(windowType);
00285 
00286         TransformFactory::getInstance()->
00287             makeContextConsistentWithPlugin(transform, plugin);
00288 
00289         configurationXml = PluginXml(plugin).toXmlString();
00290 
00291         delete dialog;
00292 
00293         if (effect && source) {
00294             source->setAuditioningPlugin(0); // will delete our plugin
00295         } else {
00296             delete plugin;
00297         }
00298     }
00299 
00300     if (ok) {
00301         m_lastConfigurations[transform.getIdentifier()] = configurationXml;
00302         input.setModel(inputModel);
00303     }
00304 
00305     return input;
00306 }
00331 ModelTransformer *
00332 ModelTransformerFactory::createTransformer(const Transform &transform,
00333                                            const ModelTransformer::Input &input)
00334 {
00335     ModelTransformer *transformer = 0;
00336 
00337     QString id = transform.getPluginIdentifier();
00338 
00339     if (FeatureExtractionPluginFactory::instanceFor(id)) {
00340 
00341         transformer =
00342             new FeatureExtractionModelTransformer(input, transform);
00343 
00344     } else if (RealTimePluginFactory::instanceFor(id)) {
00345 
00346         transformer =
00347             new RealTimeEffectModelTransformer(input, transform);
00348 
00349     } else {
00350         std::cerr << "ModelTransformerFactory::createTransformer: Unknown transform \""
00351                   << transform.getIdentifier().toStdString() << "\"" << std::endl;
00352         return transformer;
00353     }
00354 
00355     if (transformer) transformer->setObjectName(transform.getIdentifier());
00356     return transformer;
00357 }
00358 
00359 Model *
00360 ModelTransformerFactory::transform(const Transform &transform,
00361                                    const ModelTransformer::Input &input,
00362                                    QString &message)
00363 {
00364     ModelTransformer *t = createTransformer(transform, input);
00365     if (!t) return 0;
00366 
00367     connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
00368 
00369     m_runningTransformers.insert(t);
00370 
00371     t->start();
00372     Model *model = t->detachOutputModel();
00373 
00374     if (model) {
00375         QString imn = input.getModel()->objectName();
00376         QString trn =
00377             TransformFactory::getInstance()->getTransformFriendlyName
00378             (transform.getIdentifier());
00379         if (imn != "") {
00380             if (trn != "") {
00381                 model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
00382             } else {
00383                 model->setObjectName(imn);
00384             }
00385         } else if (trn != "") {
00386             model->setObjectName(trn);
00387         }
00388     } else {
00389         t->wait();
00390     }
00391 
00392     message = t->getMessage();
00393 
00394     return model;
00395 }
00396 
00397 void
00398 ModelTransformerFactory::transformerFinished()
00399 {
00400     QObject *s = sender();
00401     ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
00402     
00403     std::cerr << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << std::endl;
00404 
00405     if (!transformer) {
00406         std::cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << std::endl;
00407         return;
00408     }
00409 
00410     if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
00411         std::cerr << "WARNING: ModelTransformerFactory::transformerFinished(" 
00412                   << transformer
00413                   << "): I have no record of this transformer running!"
00414                   << std::endl;
00415     }
00416 
00417     m_runningTransformers.erase(transformer);
00418 
00419     transformer->wait(); // unnecessary but reassuring
00420     delete transformer;
00421 }
00422 
00423 void
00424 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
00425 {
00426     TransformerSet affected;
00427 
00428     for (TransformerSet::iterator i = m_runningTransformers.begin();
00429          i != m_runningTransformers.end(); ++i) {
00430 
00431         ModelTransformer *t = *i;
00432 
00433         if (t->getInputModel() == m || t->getOutputModel() == m) {
00434             affected.insert(t);
00435         }
00436     }
00437 
00438     for (TransformerSet::iterator i = affected.begin();
00439          i != affected.end(); ++i) {
00440 
00441         ModelTransformer *t = *i;
00442 
00443         t->abandon();
00444 
00445         t->wait(); // this should eventually call back on
00446                    // transformerFinished, which will remove from
00447                    // m_runningTransformers and delete.
00448     }
00449 }
00450 

Generated on Wed Feb 20 15:45:26 2008 for SonicVisualiser by  doxygen 1.5.1