annotate transform/ModelTransformerFactory.cpp @ 875:3e6ed8a8577b tonioni

Use a sparse time-value model only for outputs with fixed bin count of 1, not for those with unknown bin count. (Precursor to using more than one model for outputs with unknown bin count)
author Chris Cannam
date Tue, 28 Jan 2014 18:52:22 +0000
parents 13803edd513d
children b109b88bfa85
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@320 8
Chris@320 9 This program is free software; you can redistribute it and/or
Chris@320 10 modify it under the terms of the GNU General Public License as
Chris@320 11 published by the Free Software Foundation; either version 2 of the
Chris@320 12 License, or (at your option) any later version. See the file
Chris@320 13 COPYING included with this distribution for more information.
Chris@320 14 */
Chris@320 15
Chris@331 16 #include "ModelTransformerFactory.h"
Chris@320 17
Chris@331 18 #include "FeatureExtractionModelTransformer.h"
Chris@331 19 #include "RealTimeEffectModelTransformer.h"
Chris@320 20
Chris@332 21 #include "TransformFactory.h"
Chris@332 22
Chris@389 23 #include "base/AudioPlaySource.h"
Chris@389 24
Chris@320 25 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@320 26 #include "plugin/RealTimePluginFactory.h"
Chris@320 27 #include "plugin/PluginXml.h"
Chris@320 28
Chris@320 29 #include "data/model/DenseTimeValueModel.h"
Chris@320 30
Chris@475 31 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@320 32
Chris@320 33 #include <iostream>
Chris@320 34 #include <set>
Chris@320 35
Chris@320 36 #include <QRegExp>
Chris@320 37
Chris@850 38 using std::vector;
Chris@850 39
Chris@331 40 ModelTransformerFactory *
Chris@331 41 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
Chris@320 42
Chris@331 43 ModelTransformerFactory *
Chris@331 44 ModelTransformerFactory::getInstance()
Chris@320 45 {
Chris@320 46 return m_instance;
Chris@320 47 }
Chris@320 48
Chris@331 49 ModelTransformerFactory::~ModelTransformerFactory()
Chris@320 50 {
Chris@320 51 }
Chris@320 52
Chris@350 53 ModelTransformer::Input
Chris@350 54 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
Chris@350 55 const std::vector<Model *> &candidateInputModels,
Chris@350 56 Model *defaultInputModel,
Chris@389 57 AudioPlaySource *source,
Chris@350 58 size_t startFrame,
Chris@653 59 size_t duration,
Chris@653 60 UserConfigurator *configurator)
Chris@320 61 {
Chris@350 62 ModelTransformer::Input input(0);
Chris@350 63
Chris@350 64 if (candidateInputModels.empty()) return input;
Chris@320 65
Chris@320 66 //!!! This will need revision -- we'll have to have a callback
Chris@320 67 //from the dialog for when the candidate input model is changed,
Chris@320 68 //as we'll need to reinitialise the channel settings in the dialog
Chris@345 69 Model *inputModel = candidateInputModels[0];
Chris@320 70 QStringList candidateModelNames;
Chris@345 71 QString defaultModelName;
Chris@653 72 QMap<QString, Model *> modelMap;
Chris@320 73 for (size_t i = 0; i < candidateInputModels.size(); ++i) {
Chris@320 74 QString modelName = candidateInputModels[i]->objectName();
Chris@320 75 QString origModelName = modelName;
Chris@320 76 int dupcount = 1;
Chris@653 77 while (modelMap.contains(modelName)) {
Chris@320 78 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 79 }
Chris@320 80 modelMap[modelName] = candidateInputModels[i];
Chris@320 81 candidateModelNames.push_back(modelName);
Chris@345 82 if (candidateInputModels[i] == defaultInputModel) {
Chris@345 83 defaultModelName = modelName;
Chris@345 84 }
Chris@320 85 }
Chris@320 86
Chris@350 87 QString id = transform.getPluginIdentifier();
Chris@320 88
Chris@653 89 bool ok = true;
Chris@350 90 QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
Chris@320 91
Chris@843 92 cerr << "last configuration: " << configurationXml << endl;
Chris@320 93
Chris@320 94 Vamp::PluginBase *plugin = 0;
Chris@320 95
Chris@320 96 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 97
Chris@843 98 cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@320 99
Chris@320 100 Vamp::Plugin *vp =
Chris@320 101 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 102 (id, inputModel->getSampleRate());
Chris@320 103
Chris@653 104 plugin = vp;
Chris@320 105
Chris@320 106 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 107
Chris@320 108 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 109 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
Chris@320 110
Chris@320 111 size_t sampleRate = inputModel->getSampleRate();
Chris@320 112 size_t blockSize = 1024;
Chris@320 113 size_t channels = 1;
Chris@653 114 if (source) {
Chris@320 115 sampleRate = source->getTargetSampleRate();
Chris@320 116 blockSize = source->getTargetBlockSize();
Chris@320 117 channels = source->getTargetChannelCount();
Chris@320 118 }
Chris@320 119
Chris@320 120 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 121 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 122
Chris@320 123 plugin = rtp;
Chris@320 124 }
Chris@320 125
Chris@320 126 if (plugin) {
Chris@320 127
Chris@350 128 // Ensure block size etc are valid
Chris@350 129 TransformFactory::getInstance()->
Chris@350 130 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 131
Chris@350 132 // Prepare the plugin with any existing parameters already
Chris@350 133 // found in the transform
Chris@350 134 TransformFactory::getInstance()->
Chris@350 135 setPluginParameters(transform, plugin);
Chris@350 136
Chris@350 137 // For this interactive usage, we want to override those with
Chris@350 138 // whatever the user chose last time around
Chris@350 139 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 140
Chris@653 141 if (configurator) {
Chris@653 142 ok = configurator->configure(input, transform, plugin,
Chris@653 143 inputModel, source,
Chris@653 144 startFrame, duration,
Chris@653 145 modelMap,
Chris@653 146 candidateModelNames,
Chris@653 147 defaultModelName);
Chris@320 148 }
Chris@320 149
Chris@516 150
Chris@350 151 TransformFactory::getInstance()->
Chris@350 152 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 153
Chris@350 154 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 155
Chris@653 156 delete plugin;
Chris@320 157 }
Chris@320 158
Chris@350 159 if (ok) {
Chris@350 160 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 161 input.setModel(inputModel);
Chris@350 162 }
Chris@320 163
Chris@350 164 return input;
Chris@320 165 }
Chris@320 166
Chris@331 167 ModelTransformer *
Chris@850 168 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 169 const ModelTransformer::Input &input)
Chris@320 170 {
Chris@331 171 ModelTransformer *transformer = 0;
Chris@320 172
Chris@850 173 QString id = transforms[0].getPluginIdentifier();
Chris@320 174
Chris@320 175 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@350 176
Chris@350 177 transformer =
Chris@859 178 new FeatureExtractionModelTransformer(input, transforms);
Chris@350 179
Chris@331 180 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 181
Chris@350 182 transformer =
Chris@850 183 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 184
Chris@320 185 } else {
Chris@690 186 SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \""
Chris@850 187 << transforms[0].getIdentifier() << "\"" << endl;
Chris@331 188 return transformer;
Chris@320 189 }
Chris@320 190
Chris@850 191 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 192 return transformer;
Chris@320 193 }
Chris@320 194
Chris@320 195 Model *
Chris@350 196 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 197 const ModelTransformer::Input &input,
Chris@848 198 QString &message)
Chris@320 199 {
Chris@690 200 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 201
Chris@850 202 Transforms transforms;
Chris@850 203 transforms.push_back(transform);
Chris@850 204 vector<Model *> mm = transformMultiple(transforms, input, message);
Chris@850 205 if (mm.empty()) return 0;
Chris@850 206 else return mm[0];
Chris@320 207 }
Chris@320 208
Chris@849 209 vector<Model *>
Chris@849 210 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 211 const ModelTransformer::Input &input,
Chris@849 212 QString &message)
Chris@849 213 {
Chris@849 214 SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
Chris@849 215
Chris@849 216 ModelTransformer *t = createTransformer(transforms, input);
Chris@850 217 if (!t) return vector<Model *>();
Chris@849 218
Chris@849 219 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@849 220
Chris@849 221 m_runningTransformers.insert(t);
Chris@849 222
Chris@849 223 t->start();
Chris@850 224 vector<Model *> models = t->detachOutputModels();
Chris@849 225
Chris@850 226 if (!models.empty()) {
Chris@849 227 QString imn = input.getModel()->objectName();
Chris@849 228 QString trn =
Chris@849 229 TransformFactory::getInstance()->getTransformFriendlyName
Chris@850 230 (transforms[0].getIdentifier());
Chris@850 231 for (int i = 0; i < models.size(); ++i) {
Chris@850 232 if (imn != "") {
Chris@850 233 if (trn != "") {
Chris@850 234 models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@850 235 } else {
Chris@850 236 models[i]->setObjectName(imn);
Chris@850 237 }
Chris@850 238 } else if (trn != "") {
Chris@850 239 models[i]->setObjectName(trn);
Chris@849 240 }
Chris@849 241 }
Chris@849 242 } else {
Chris@849 243 t->wait();
Chris@849 244 }
Chris@849 245
Chris@849 246 message = t->getMessage();
Chris@849 247
Chris@850 248 return models;
Chris@849 249 }
Chris@849 250
Chris@320 251 void
Chris@331 252 ModelTransformerFactory::transformerFinished()
Chris@320 253 {
Chris@320 254 QObject *s = sender();
Chris@331 255 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 256
Chris@690 257 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
Chris@320 258
Chris@331 259 if (!transformer) {
Chris@843 260 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
Chris@320 261 return;
Chris@320 262 }
Chris@320 263
Chris@331 264 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@843 265 cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 266 << transformer
Chris@331 267 << "): I have no record of this transformer running!"
Chris@843 268 << endl;
Chris@320 269 }
Chris@320 270
Chris@331 271 m_runningTransformers.erase(transformer);
Chris@320 272
Chris@331 273 transformer->wait(); // unnecessary but reassuring
Chris@331 274 delete transformer;
Chris@320 275 }
Chris@320 276
Chris@320 277 void
Chris@331 278 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 279 {
Chris@328 280 TransformerSet affected;
Chris@320 281
Chris@328 282 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 283 i != m_runningTransformers.end(); ++i) {
Chris@320 284
Chris@331 285 ModelTransformer *t = *i;
Chris@320 286
Chris@850 287 if (t->getInputModel() == m) {
Chris@320 288 affected.insert(t);
Chris@850 289 } else {
Chris@850 290 vector<Model *> mm = t->getOutputModels();
Chris@850 291 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@850 292 if (mm[i] == m) affected.insert(t);
Chris@850 293 }
Chris@320 294 }
Chris@320 295 }
Chris@320 296
Chris@328 297 for (TransformerSet::iterator i = affected.begin();
Chris@320 298 i != affected.end(); ++i) {
Chris@320 299
Chris@331 300 ModelTransformer *t = *i;
Chris@320 301
Chris@320 302 t->abandon();
Chris@320 303
Chris@320 304 t->wait(); // this should eventually call back on
Chris@331 305 // transformerFinished, which will remove from
Chris@328 306 // m_runningTransformers and delete.
Chris@320 307 }
Chris@320 308 }
Chris@320 309