annotate transform/ModelTransformerFactory.cpp @ 1247:8f076d02569a piper

Make SVDEBUG always write to a log file -- formerly this was disabled in NDEBUG builds. I think there's little use to that, it just means that we keep adding more cerr debug output because we aren't getting the log we need. And SVDEBUG logging is not usually used in tight loops, I don't think the performance overhead is too serious. Also update the About box.
author Chris Cannam
date Thu, 03 Nov 2016 14:57:00 +0000
parents ba16388b937d
children a99641535e02
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@843 92 cerr << "last configuration: " << 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@320 98 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 99
Chris@1040 100 sv_samplerate_t sampleRate = inputModel->getSampleRate();
Chris@930 101 int blockSize = 1024;
Chris@930 102 int channels = 1;
Chris@653 103 if (source) {
Chris@320 104 sampleRate = source->getTargetSampleRate();
Chris@320 105 blockSize = source->getTargetBlockSize();
Chris@320 106 channels = source->getTargetChannelCount();
Chris@320 107 }
Chris@320 108
Chris@320 109 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 110 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 111
Chris@320 112 plugin = rtp;
Chris@1225 113
Chris@1225 114 } else {
Chris@1225 115
Chris@1225 116 cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@1225 117
Chris@1225 118 Vamp::Plugin *vp =
Chris@1225 119 FeatureExtractionPluginFactory::instance()->instantiatePlugin
Chris@1225 120 (id, float(inputModel->getSampleRate()));
Chris@1225 121
Chris@1225 122 plugin = vp;
Chris@320 123 }
Chris@320 124
Chris@320 125 if (plugin) {
Chris@320 126
Chris@350 127 // Ensure block size etc are valid
Chris@350 128 TransformFactory::getInstance()->
Chris@350 129 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 130
Chris@350 131 // Prepare the plugin with any existing parameters already
Chris@350 132 // found in the transform
Chris@350 133 TransformFactory::getInstance()->
Chris@350 134 setPluginParameters(transform, plugin);
Chris@350 135
Chris@350 136 // For this interactive usage, we want to override those with
Chris@350 137 // whatever the user chose last time around
Chris@350 138 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 139
Chris@653 140 if (configurator) {
Chris@653 141 ok = configurator->configure(input, transform, plugin,
Chris@653 142 inputModel, source,
Chris@653 143 startFrame, duration,
Chris@653 144 modelMap,
Chris@653 145 candidateModelNames,
Chris@653 146 defaultModelName);
Chris@320 147 }
Chris@320 148
Chris@516 149
Chris@350 150 TransformFactory::getInstance()->
Chris@350 151 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 152
Chris@350 153 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 154
Chris@653 155 delete plugin;
Chris@320 156 }
Chris@320 157
Chris@350 158 if (ok) {
Chris@350 159 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 160 input.setModel(inputModel);
Chris@350 161 }
Chris@320 162
Chris@350 163 return input;
Chris@320 164 }
Chris@320 165
Chris@331 166 ModelTransformer *
Chris@850 167 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 168 const ModelTransformer::Input &input)
Chris@320 169 {
Chris@331 170 ModelTransformer *transformer = 0;
Chris@320 171
Chris@850 172 QString id = transforms[0].getPluginIdentifier();
Chris@320 173
Chris@1225 174 if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 175
Chris@350 176 transformer =
Chris@850 177 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 178
Chris@320 179 } else {
Chris@1225 180
Chris@1225 181 transformer =
Chris@1225 182 new FeatureExtractionModelTransformer(input, transforms);
Chris@320 183 }
Chris@320 184
Chris@850 185 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 186 return transformer;
Chris@320 187 }
Chris@320 188
Chris@320 189 Model *
Chris@350 190 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 191 const ModelTransformer::Input &input,
Chris@877 192 QString &message,
Chris@877 193 AdditionalModelHandler *handler)
Chris@320 194 {
Chris@690 195 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 196
Chris@850 197 Transforms transforms;
Chris@850 198 transforms.push_back(transform);
Chris@877 199 vector<Model *> mm = transformMultiple(transforms, input, message, handler);
Chris@850 200 if (mm.empty()) return 0;
Chris@850 201 else return mm[0];
Chris@320 202 }
Chris@320 203
Chris@849 204 vector<Model *>
Chris@849 205 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 206 const ModelTransformer::Input &input,
Chris@877 207 QString &message,
Chris@877 208 AdditionalModelHandler *handler)
Chris@849 209 {
Chris@849 210 SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
Chris@849 211
Chris@849 212 ModelTransformer *t = createTransformer(transforms, input);
Chris@850 213 if (!t) return vector<Model *>();
Chris@849 214
Chris@877 215 if (handler) {
Chris@877 216 m_handlers[t] = handler;
Chris@877 217 }
Chris@849 218
Chris@849 219 m_runningTransformers.insert(t);
Chris@849 220
Chris@877 221 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@877 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@924 231 for (int i = 0; i < (int)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@877 273 if (m_handlers.find(transformer) != m_handlers.end()) {
Chris@877 274 if (transformer->willHaveAdditionalOutputModels()) {
Chris@877 275 vector<Model *> mm = transformer->detachAdditionalOutputModels();
Chris@877 276 m_handlers[transformer]->moreModelsAvailable(mm);
Chris@878 277 } else {
Chris@878 278 m_handlers[transformer]->noMoreModelsAvailable();
Chris@877 279 }
Chris@877 280 m_handlers.erase(transformer);
Chris@877 281 }
Chris@877 282
Chris@1079 283 if (transformer->isAbandoned()) {
Chris@1079 284 if (transformer->getMessage() != "") {
Chris@1079 285 emit transformFailed("", transformer->getMessage());
Chris@1079 286 }
Chris@1079 287 }
Chris@1079 288
Chris@331 289 transformer->wait(); // unnecessary but reassuring
Chris@331 290 delete transformer;
Chris@320 291 }
Chris@320 292
Chris@320 293 void
Chris@331 294 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 295 {
Chris@328 296 TransformerSet affected;
Chris@320 297
Chris@328 298 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 299 i != m_runningTransformers.end(); ++i) {
Chris@320 300
Chris@331 301 ModelTransformer *t = *i;
Chris@320 302
Chris@850 303 if (t->getInputModel() == m) {
Chris@320 304 affected.insert(t);
Chris@850 305 } else {
Chris@850 306 vector<Model *> mm = t->getOutputModels();
Chris@850 307 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@850 308 if (mm[i] == m) affected.insert(t);
Chris@850 309 }
Chris@320 310 }
Chris@320 311 }
Chris@320 312
Chris@328 313 for (TransformerSet::iterator i = affected.begin();
Chris@320 314 i != affected.end(); ++i) {
Chris@320 315
Chris@331 316 ModelTransformer *t = *i;
Chris@320 317
Chris@320 318 t->abandon();
Chris@320 319
Chris@320 320 t->wait(); // this should eventually call back on
Chris@331 321 // transformerFinished, which will remove from
Chris@328 322 // m_runningTransformers and delete.
Chris@320 323 }
Chris@320 324 }
Chris@320 325