annotate transform/ModelTransformerFactory.cpp @ 1455:ec9e65fcf749

The use of the begin/end pairs here just seems to cause too many rows to be deleted (from the visual representation, not the underlying model). Things apparently work better if we just modify the underlying model and let the change signals percolate back up again. To that end, update the change handlers so as to cover their proper ranges with dataChanged signals.
author Chris Cannam
date Mon, 23 Apr 2018 16:03:35 +0100
parents 48e9f538e6e9
children 70e172e6cc59
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@1048 58 sv_frame_t startFrame,
Chris@1048 59 sv_frame_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@930 73 for (int i = 0; i < (int)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@1264 92 SVDEBUG << "ModelTransformer: last configuration for identifier " << transform.getIdentifier() << ": " << configurationXml << endl;
Chris@320 93
Chris@320 94 Vamp::PluginBase *plugin = 0;
Chris@320 95
Chris@1225 96 if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 97
Chris@1264 98 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating real-time plugin" << endl;
Chris@1264 99
Chris@320 100 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 101
Chris@1040 102 sv_samplerate_t sampleRate = inputModel->getSampleRate();
Chris@930 103 int blockSize = 1024;
Chris@930 104 int channels = 1;
Chris@653 105 if (source) {
Chris@1321 106 sampleRate = source->getSourceSampleRate();
Chris@320 107 blockSize = source->getTargetBlockSize();
Chris@320 108 channels = source->getTargetChannelCount();
Chris@320 109 }
Chris@320 110
Chris@320 111 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 112 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 113
Chris@320 114 plugin = rtp;
Chris@1225 115
Chris@1225 116 } else {
Chris@1225 117
Chris@1264 118 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@1225 119
Chris@1225 120 Vamp::Plugin *vp =
Chris@1225 121 FeatureExtractionPluginFactory::instance()->instantiatePlugin
Chris@1225 122 (id, float(inputModel->getSampleRate()));
Chris@1225 123
Chris@1225 124 plugin = vp;
Chris@320 125 }
Chris@320 126
Chris@320 127 if (plugin) {
Chris@320 128
Chris@350 129 // Ensure block size etc are valid
Chris@350 130 TransformFactory::getInstance()->
Chris@350 131 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 132
Chris@350 133 // Prepare the plugin with any existing parameters already
Chris@350 134 // found in the transform
Chris@350 135 TransformFactory::getInstance()->
Chris@350 136 setPluginParameters(transform, plugin);
Chris@350 137
Chris@350 138 // For this interactive usage, we want to override those with
Chris@350 139 // whatever the user chose last time around
Chris@350 140 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 141
Chris@653 142 if (configurator) {
Chris@653 143 ok = configurator->configure(input, transform, plugin,
Chris@653 144 inputModel, source,
Chris@653 145 startFrame, duration,
Chris@653 146 modelMap,
Chris@653 147 candidateModelNames,
Chris@653 148 defaultModelName);
Chris@320 149 }
Chris@320 150
Chris@516 151
Chris@350 152 TransformFactory::getInstance()->
Chris@350 153 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 154
Chris@350 155 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 156
Chris@1264 157 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: got configuration, deleting plugin" << endl;
Chris@1264 158
Chris@653 159 delete plugin;
Chris@320 160 }
Chris@320 161
Chris@350 162 if (ok) {
Chris@350 163 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 164 input.setModel(inputModel);
Chris@350 165 }
Chris@320 166
Chris@350 167 return input;
Chris@320 168 }
Chris@320 169
Chris@331 170 ModelTransformer *
Chris@850 171 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 172 const ModelTransformer::Input &input)
Chris@320 173 {
Chris@331 174 ModelTransformer *transformer = 0;
Chris@320 175
Chris@850 176 QString id = transforms[0].getPluginIdentifier();
Chris@320 177
Chris@1225 178 if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 179
Chris@350 180 transformer =
Chris@850 181 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 182
Chris@320 183 } else {
Chris@1225 184
Chris@1225 185 transformer =
Chris@1225 186 new FeatureExtractionModelTransformer(input, transforms);
Chris@320 187 }
Chris@320 188
Chris@850 189 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 190 return transformer;
Chris@320 191 }
Chris@320 192
Chris@320 193 Model *
Chris@350 194 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 195 const ModelTransformer::Input &input,
Chris@877 196 QString &message,
Chris@877 197 AdditionalModelHandler *handler)
Chris@320 198 {
Chris@690 199 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 200
Chris@850 201 Transforms transforms;
Chris@850 202 transforms.push_back(transform);
Chris@877 203 vector<Model *> mm = transformMultiple(transforms, input, message, handler);
Chris@850 204 if (mm.empty()) return 0;
Chris@850 205 else return mm[0];
Chris@320 206 }
Chris@320 207
Chris@849 208 vector<Model *>
Chris@849 209 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 210 const ModelTransformer::Input &input,
Chris@877 211 QString &message,
Chris@877 212 AdditionalModelHandler *handler)
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@877 219 if (handler) {
Chris@877 220 m_handlers[t] = handler;
Chris@877 221 }
Chris@849 222
Chris@849 223 m_runningTransformers.insert(t);
Chris@849 224
Chris@877 225 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@877 226
Chris@849 227 t->start();
Chris@850 228 vector<Model *> models = t->detachOutputModels();
Chris@849 229
Chris@850 230 if (!models.empty()) {
Chris@849 231 QString imn = input.getModel()->objectName();
Chris@849 232 QString trn =
Chris@849 233 TransformFactory::getInstance()->getTransformFriendlyName
Chris@850 234 (transforms[0].getIdentifier());
Chris@924 235 for (int i = 0; i < (int)models.size(); ++i) {
Chris@850 236 if (imn != "") {
Chris@850 237 if (trn != "") {
Chris@850 238 models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@850 239 } else {
Chris@850 240 models[i]->setObjectName(imn);
Chris@850 241 }
Chris@850 242 } else if (trn != "") {
Chris@850 243 models[i]->setObjectName(trn);
Chris@849 244 }
Chris@849 245 }
Chris@849 246 } else {
Chris@849 247 t->wait();
Chris@849 248 }
Chris@849 249
Chris@849 250 message = t->getMessage();
Chris@849 251
Chris@850 252 return models;
Chris@849 253 }
Chris@849 254
Chris@320 255 void
Chris@331 256 ModelTransformerFactory::transformerFinished()
Chris@320 257 {
Chris@320 258 QObject *s = sender();
Chris@331 259 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 260
Chris@690 261 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
Chris@320 262
Chris@331 263 if (!transformer) {
Chris@1429 264 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
Chris@1429 265 return;
Chris@320 266 }
Chris@320 267
Chris@331 268 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@843 269 cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 270 << transformer
Chris@331 271 << "): I have no record of this transformer running!"
Chris@843 272 << endl;
Chris@320 273 }
Chris@320 274
Chris@331 275 m_runningTransformers.erase(transformer);
Chris@320 276
Chris@877 277 if (m_handlers.find(transformer) != m_handlers.end()) {
Chris@877 278 if (transformer->willHaveAdditionalOutputModels()) {
Chris@877 279 vector<Model *> mm = transformer->detachAdditionalOutputModels();
Chris@877 280 m_handlers[transformer]->moreModelsAvailable(mm);
Chris@878 281 } else {
Chris@878 282 m_handlers[transformer]->noMoreModelsAvailable();
Chris@877 283 }
Chris@877 284 m_handlers.erase(transformer);
Chris@877 285 }
Chris@877 286
Chris@1079 287 if (transformer->isAbandoned()) {
Chris@1079 288 if (transformer->getMessage() != "") {
Chris@1079 289 emit transformFailed("", transformer->getMessage());
Chris@1079 290 }
Chris@1079 291 }
Chris@1079 292
Chris@331 293 transformer->wait(); // unnecessary but reassuring
Chris@331 294 delete transformer;
Chris@320 295 }
Chris@320 296
Chris@320 297 void
Chris@331 298 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 299 {
Chris@328 300 TransformerSet affected;
Chris@320 301
Chris@328 302 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 303 i != m_runningTransformers.end(); ++i) {
Chris@320 304
Chris@331 305 ModelTransformer *t = *i;
Chris@320 306
Chris@850 307 if (t->getInputModel() == m) {
Chris@320 308 affected.insert(t);
Chris@850 309 } else {
Chris@850 310 vector<Model *> mm = t->getOutputModels();
Chris@850 311 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@850 312 if (mm[i] == m) affected.insert(t);
Chris@850 313 }
Chris@320 314 }
Chris@320 315 }
Chris@320 316
Chris@328 317 for (TransformerSet::iterator i = affected.begin();
Chris@320 318 i != affected.end(); ++i) {
Chris@320 319
Chris@331 320 ModelTransformer *t = *i;
Chris@320 321
Chris@320 322 t->abandon();
Chris@320 323
Chris@320 324 t->wait(); // this should eventually call back on
Chris@331 325 // transformerFinished, which will remove from
Chris@328 326 // m_runningTransformers and delete.
Chris@320 327 }
Chris@320 328 }
Chris@320 329