annotate transform/ModelTransformerFactory.cpp @ 1725:78fe29adfd16

Re-implement extendEndFrame behaviour, used by Tony application
author Chris Cannam
date Wed, 19 Jun 2019 13:32:52 +0100
parents b17fb3a4560c
children 8efce64dd85e
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@1703 37 #include <QMutexLocker>
Chris@320 38
Chris@850 39 using std::vector;
Chris@850 40
Chris@331 41 ModelTransformerFactory *
Chris@331 42 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
Chris@320 43
Chris@331 44 ModelTransformerFactory *
Chris@331 45 ModelTransformerFactory::getInstance()
Chris@320 46 {
Chris@320 47 return m_instance;
Chris@320 48 }
Chris@320 49
Chris@331 50 ModelTransformerFactory::~ModelTransformerFactory()
Chris@320 51 {
Chris@320 52 }
Chris@320 53
Chris@350 54 ModelTransformer::Input
Chris@350 55 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
Chris@350 56 const std::vector<Model *> &candidateInputModels,
Chris@350 57 Model *defaultInputModel,
Chris@389 58 AudioPlaySource *source,
Chris@1048 59 sv_frame_t startFrame,
Chris@1048 60 sv_frame_t duration,
Chris@653 61 UserConfigurator *configurator)
Chris@320 62 {
Chris@1703 63 QMutexLocker locker(&m_mutex);
Chris@1703 64
Chris@1582 65 ModelTransformer::Input input(nullptr);
Chris@350 66
Chris@350 67 if (candidateInputModels.empty()) return input;
Chris@320 68
Chris@320 69 //!!! This will need revision -- we'll have to have a callback
Chris@320 70 //from the dialog for when the candidate input model is changed,
Chris@320 71 //as we'll need to reinitialise the channel settings in the dialog
Chris@345 72 Model *inputModel = candidateInputModels[0];
Chris@320 73 QStringList candidateModelNames;
Chris@345 74 QString defaultModelName;
Chris@653 75 QMap<QString, Model *> modelMap;
Chris@930 76 for (int i = 0; i < (int)candidateInputModels.size(); ++i) {
Chris@320 77 QString modelName = candidateInputModels[i]->objectName();
Chris@320 78 QString origModelName = modelName;
Chris@320 79 int dupcount = 1;
Chris@653 80 while (modelMap.contains(modelName)) {
Chris@320 81 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 82 }
Chris@320 83 modelMap[modelName] = candidateInputModels[i];
Chris@320 84 candidateModelNames.push_back(modelName);
Chris@345 85 if (candidateInputModels[i] == defaultInputModel) {
Chris@345 86 defaultModelName = modelName;
Chris@345 87 }
Chris@320 88 }
Chris@320 89
Chris@350 90 QString id = transform.getPluginIdentifier();
Chris@320 91
Chris@653 92 bool ok = true;
Chris@350 93 QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
Chris@320 94
Chris@1264 95 SVDEBUG << "ModelTransformer: last configuration for identifier " << transform.getIdentifier() << ": " << configurationXml << endl;
Chris@320 96
Chris@1582 97 Vamp::PluginBase *plugin = nullptr;
Chris@320 98
Chris@1225 99 if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 100
Chris@1264 101 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating real-time plugin" << endl;
Chris@1264 102
Chris@320 103 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 104
Chris@1040 105 sv_samplerate_t sampleRate = inputModel->getSampleRate();
Chris@930 106 int blockSize = 1024;
Chris@930 107 int channels = 1;
Chris@653 108 if (source) {
Chris@1321 109 sampleRate = source->getSourceSampleRate();
Chris@320 110 blockSize = source->getTargetBlockSize();
Chris@320 111 channels = source->getTargetChannelCount();
Chris@320 112 }
Chris@320 113
Chris@320 114 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 115 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 116
Chris@320 117 plugin = rtp;
Chris@1225 118
Chris@1225 119 } else {
Chris@1225 120
Chris@1264 121 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@1225 122
Chris@1225 123 Vamp::Plugin *vp =
Chris@1225 124 FeatureExtractionPluginFactory::instance()->instantiatePlugin
Chris@1225 125 (id, float(inputModel->getSampleRate()));
Chris@1225 126
Chris@1225 127 plugin = vp;
Chris@320 128 }
Chris@320 129
Chris@320 130 if (plugin) {
Chris@320 131
Chris@350 132 // Ensure block size etc are valid
Chris@350 133 TransformFactory::getInstance()->
Chris@350 134 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 135
Chris@350 136 // Prepare the plugin with any existing parameters already
Chris@350 137 // found in the transform
Chris@350 138 TransformFactory::getInstance()->
Chris@350 139 setPluginParameters(transform, plugin);
Chris@350 140
Chris@350 141 // For this interactive usage, we want to override those with
Chris@350 142 // whatever the user chose last time around
Chris@350 143 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 144
Chris@653 145 if (configurator) {
Chris@653 146 ok = configurator->configure(input, transform, plugin,
Chris@653 147 inputModel, source,
Chris@653 148 startFrame, duration,
Chris@653 149 modelMap,
Chris@653 150 candidateModelNames,
Chris@653 151 defaultModelName);
Chris@320 152 }
Chris@320 153
Chris@516 154
Chris@350 155 TransformFactory::getInstance()->
Chris@350 156 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 157
Chris@350 158 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 159
Chris@1264 160 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: got configuration, deleting plugin" << endl;
Chris@1264 161
Chris@653 162 delete plugin;
Chris@320 163 }
Chris@320 164
Chris@350 165 if (ok) {
Chris@350 166 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 167 input.setModel(inputModel);
Chris@350 168 }
Chris@320 169
Chris@350 170 return input;
Chris@320 171 }
Chris@320 172
Chris@331 173 ModelTransformer *
Chris@850 174 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 175 const ModelTransformer::Input &input)
Chris@320 176 {
Chris@1582 177 ModelTransformer *transformer = nullptr;
Chris@320 178
Chris@850 179 QString id = transforms[0].getPluginIdentifier();
Chris@320 180
Chris@1225 181 if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 182
Chris@350 183 transformer =
Chris@850 184 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 185
Chris@320 186 } else {
Chris@1225 187
Chris@1225 188 transformer =
Chris@1225 189 new FeatureExtractionModelTransformer(input, transforms);
Chris@320 190 }
Chris@320 191
Chris@850 192 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 193 return transformer;
Chris@320 194 }
Chris@320 195
Chris@320 196 Model *
Chris@350 197 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 198 const ModelTransformer::Input &input,
Chris@877 199 QString &message,
Chris@877 200 AdditionalModelHandler *handler)
Chris@320 201 {
Chris@690 202 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 203
Chris@850 204 Transforms transforms;
Chris@850 205 transforms.push_back(transform);
Chris@877 206 vector<Model *> mm = transformMultiple(transforms, input, message, handler);
Chris@1582 207 if (mm.empty()) return nullptr;
Chris@850 208 else return mm[0];
Chris@320 209 }
Chris@320 210
Chris@849 211 vector<Model *>
Chris@849 212 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 213 const ModelTransformer::Input &input,
Chris@877 214 QString &message,
Chris@877 215 AdditionalModelHandler *handler)
Chris@849 216 {
Chris@849 217 SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
Chris@849 218
Chris@1703 219 QMutexLocker locker(&m_mutex);
Chris@1703 220
Chris@849 221 ModelTransformer *t = createTransformer(transforms, input);
Chris@850 222 if (!t) return vector<Model *>();
Chris@849 223
Chris@877 224 if (handler) {
Chris@877 225 m_handlers[t] = handler;
Chris@877 226 }
Chris@849 227
Chris@849 228 m_runningTransformers.insert(t);
Chris@849 229
Chris@877 230 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@877 231
Chris@849 232 t->start();
Chris@850 233 vector<Model *> models = t->detachOutputModels();
Chris@849 234
Chris@850 235 if (!models.empty()) {
Chris@849 236 QString imn = input.getModel()->objectName();
Chris@849 237 QString trn =
Chris@849 238 TransformFactory::getInstance()->getTransformFriendlyName
Chris@850 239 (transforms[0].getIdentifier());
Chris@924 240 for (int i = 0; i < (int)models.size(); ++i) {
Chris@850 241 if (imn != "") {
Chris@850 242 if (trn != "") {
Chris@850 243 models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@850 244 } else {
Chris@850 245 models[i]->setObjectName(imn);
Chris@850 246 }
Chris@850 247 } else if (trn != "") {
Chris@850 248 models[i]->setObjectName(trn);
Chris@849 249 }
Chris@849 250 }
Chris@849 251 } else {
Chris@849 252 t->wait();
Chris@849 253 }
Chris@849 254
Chris@849 255 message = t->getMessage();
Chris@849 256
Chris@850 257 return models;
Chris@849 258 }
Chris@849 259
Chris@320 260 void
Chris@331 261 ModelTransformerFactory::transformerFinished()
Chris@320 262 {
Chris@1703 263 QMutexLocker locker(&m_mutex);
Chris@1703 264
Chris@320 265 QObject *s = sender();
Chris@331 266 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 267
Chris@690 268 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
Chris@320 269
Chris@331 270 if (!transformer) {
Chris@1429 271 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
Chris@1429 272 return;
Chris@320 273 }
Chris@320 274
Chris@331 275 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@843 276 cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 277 << transformer
Chris@331 278 << "): I have no record of this transformer running!"
Chris@843 279 << endl;
Chris@320 280 }
Chris@320 281
Chris@331 282 m_runningTransformers.erase(transformer);
Chris@320 283
Chris@877 284 if (m_handlers.find(transformer) != m_handlers.end()) {
Chris@877 285 if (transformer->willHaveAdditionalOutputModels()) {
Chris@877 286 vector<Model *> mm = transformer->detachAdditionalOutputModels();
Chris@877 287 m_handlers[transformer]->moreModelsAvailable(mm);
Chris@878 288 } else {
Chris@878 289 m_handlers[transformer]->noMoreModelsAvailable();
Chris@877 290 }
Chris@877 291 m_handlers.erase(transformer);
Chris@877 292 }
Chris@877 293
Chris@1079 294 if (transformer->isAbandoned()) {
Chris@1079 295 if (transformer->getMessage() != "") {
Chris@1079 296 emit transformFailed("", transformer->getMessage());
Chris@1079 297 }
Chris@1079 298 }
Chris@1079 299
Chris@331 300 transformer->wait(); // unnecessary but reassuring
Chris@331 301 delete transformer;
Chris@320 302 }
Chris@320 303
Chris@320 304 void
Chris@331 305 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 306 {
Chris@328 307 TransformerSet affected;
Chris@320 308
Chris@1703 309 {
Chris@1703 310 QMutexLocker locker(&m_mutex);
Chris@1703 311
Chris@1703 312 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@1703 313 i != m_runningTransformers.end(); ++i) {
Chris@320 314
Chris@1703 315 ModelTransformer *t = *i;
Chris@320 316
Chris@1703 317 if (t->getInputModel() == m) {
Chris@1703 318 affected.insert(t);
Chris@1703 319 } else {
Chris@1703 320 vector<Model *> mm = t->getOutputModels();
Chris@1703 321 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@1703 322 if (mm[i] == m) affected.insert(t);
Chris@1703 323 }
Chris@850 324 }
Chris@320 325 }
Chris@320 326 }
Chris@320 327
Chris@328 328 for (TransformerSet::iterator i = affected.begin();
Chris@320 329 i != affected.end(); ++i) {
Chris@320 330
Chris@331 331 ModelTransformer *t = *i;
Chris@320 332
Chris@320 333 t->abandon();
Chris@320 334
Chris@320 335 t->wait(); // this should eventually call back on
Chris@331 336 // transformerFinished, which will remove from
Chris@328 337 // m_runningTransformers and delete.
Chris@320 338 }
Chris@320 339 }
Chris@320 340
Chris@1703 341 bool
Chris@1703 342 ModelTransformerFactory::haveRunningTransformers() const
Chris@1703 343 {
Chris@1703 344 QMutexLocker locker(&m_mutex);
Chris@1703 345
Chris@1703 346 return (!m_runningTransformers.empty());
Chris@1703 347 }