svcore  1.9
ModelTransformerFactory.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
17 
20 
21 #include "TransformFactory.h"
22 
23 #include "base/AudioPlaySource.h"
24 
27 #include "plugin/PluginXml.h"
28 
30 
31 #include <vamp-hostsdk/PluginHostAdapter.h>
32 
33 #include <iostream>
34 #include <set>
35 
36 #include <QRegExp>
37 
38 using std::vector;
39 
42 
45 {
46  return m_instance;
47 }
48 
50 {
51 }
52 
55  const std::vector<Model *> &candidateInputModels,
56  Model *defaultInputModel,
57  AudioPlaySource *source,
58  int startFrame,
59  int duration,
60  UserConfigurator *configurator)
61 {
62  ModelTransformer::Input input(0);
63 
64  if (candidateInputModels.empty()) return input;
65 
67  //from the dialog for when the candidate input model is changed,
68  //as we'll need to reinitialise the channel settings in the dialog
69  Model *inputModel = candidateInputModels[0];
70  QStringList candidateModelNames;
71  QString defaultModelName;
72  QMap<QString, Model *> modelMap;
73  for (int i = 0; i < (int)candidateInputModels.size(); ++i) {
74  QString modelName = candidateInputModels[i]->objectName();
75  QString origModelName = modelName;
76  int dupcount = 1;
77  while (modelMap.contains(modelName)) {
78  modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
79  }
80  modelMap[modelName] = candidateInputModels[i];
81  candidateModelNames.push_back(modelName);
82  if (candidateInputModels[i] == defaultInputModel) {
83  defaultModelName = modelName;
84  }
85  }
86 
87  QString id = transform.getPluginIdentifier();
88 
89  bool ok = true;
90  QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
91 
92  cerr << "last configuration: " << configurationXml << endl;
93 
94  Vamp::PluginBase *plugin = 0;
95 
97 
98  cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl;
99 
100  Vamp::Plugin *vp =
102  (id, inputModel->getSampleRate());
103 
104  plugin = vp;
105 
106  } else if (RealTimePluginFactory::instanceFor(id)) {
107 
109 
110  int sampleRate = inputModel->getSampleRate();
111  int blockSize = 1024;
112  int channels = 1;
113  if (source) {
114  sampleRate = source->getTargetSampleRate();
115  blockSize = source->getTargetBlockSize();
116  channels = source->getTargetChannelCount();
117  }
118 
120  (id, 0, 0, sampleRate, blockSize, channels);
121 
122  plugin = rtp;
123  }
124 
125  if (plugin) {
126 
127  // Ensure block size etc are valid
129  makeContextConsistentWithPlugin(transform, plugin);
130 
131  // Prepare the plugin with any existing parameters already
132  // found in the transform
134  setPluginParameters(transform, plugin);
135 
136  // For this interactive usage, we want to override those with
137  // whatever the user chose last time around
138  PluginXml(plugin).setParametersFromXml(configurationXml);
139 
140  if (configurator) {
141  ok = configurator->configure(input, transform, plugin,
142  inputModel, source,
143  startFrame, duration,
144  modelMap,
145  candidateModelNames,
146  defaultModelName);
147  }
148 
149 
151  makeContextConsistentWithPlugin(transform, plugin);
152 
153  configurationXml = PluginXml(plugin).toXmlString();
154 
155  delete plugin;
156  }
157 
158  if (ok) {
159  m_lastConfigurations[transform.getIdentifier()] = configurationXml;
160  input.setModel(inputModel);
161  }
162 
163  return input;
164 }
165 
168  const ModelTransformer::Input &input)
169 {
170  ModelTransformer *transformer = 0;
171 
172  QString id = transforms[0].getPluginIdentifier();
173 
175 
176  transformer =
177  new FeatureExtractionModelTransformer(input, transforms);
178 
179  } else if (RealTimePluginFactory::instanceFor(id)) {
180 
181  transformer =
182  new RealTimeEffectModelTransformer(input, transforms[0]);
183 
184  } else {
185  SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \""
186  << transforms[0].getIdentifier() << "\"" << endl;
187  return transformer;
188  }
189 
190  if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
191  return transformer;
192 }
193 
194 Model *
196  const ModelTransformer::Input &input,
197  QString &message,
198  AdditionalModelHandler *handler)
199 {
200  SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
201 
202  Transforms transforms;
203  transforms.push_back(transform);
204  vector<Model *> mm = transformMultiple(transforms, input, message, handler);
205  if (mm.empty()) return 0;
206  else return mm[0];
207 }
208 
209 vector<Model *>
211  const ModelTransformer::Input &input,
212  QString &message,
213  AdditionalModelHandler *handler)
214 {
215  SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
216 
217  ModelTransformer *t = createTransformer(transforms, input);
218  if (!t) return vector<Model *>();
219 
220  if (handler) {
221  m_handlers[t] = handler;
222  }
223 
224  m_runningTransformers.insert(t);
225 
226  connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
227 
228  t->start();
229  vector<Model *> models = t->detachOutputModels();
230 
231  if (!models.empty()) {
232  QString imn = input.getModel()->objectName();
233  QString trn =
235  (transforms[0].getIdentifier());
236  for (int i = 0; i < (int)models.size(); ++i) {
237  if (imn != "") {
238  if (trn != "") {
239  models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
240  } else {
241  models[i]->setObjectName(imn);
242  }
243  } else if (trn != "") {
244  models[i]->setObjectName(trn);
245  }
246  }
247  } else {
248  t->wait();
249  }
250 
251  message = t->getMessage();
252 
253  return models;
254 }
255 
256 void
258 {
259  QObject *s = sender();
260  ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
261 
262 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
263 
264  if (!transformer) {
265  cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
266  return;
267  }
268 
269  if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
270  cerr << "WARNING: ModelTransformerFactory::transformerFinished("
271  << transformer
272  << "): I have no record of this transformer running!"
273  << endl;
274  }
275 
276  m_runningTransformers.erase(transformer);
277 
278  if (m_handlers.find(transformer) != m_handlers.end()) {
279  if (transformer->willHaveAdditionalOutputModels()) {
280  vector<Model *> mm = transformer->detachAdditionalOutputModels();
281  m_handlers[transformer]->moreModelsAvailable(mm);
282  } else {
283  m_handlers[transformer]->noMoreModelsAvailable();
284  }
285  m_handlers.erase(transformer);
286  }
287 
288  transformer->wait(); // unnecessary but reassuring
289  delete transformer;
290 }
291 
292 void
294 {
295  TransformerSet affected;
296 
297  for (TransformerSet::iterator i = m_runningTransformers.begin();
298  i != m_runningTransformers.end(); ++i) {
299 
300  ModelTransformer *t = *i;
301 
302  if (t->getInputModel() == m) {
303  affected.insert(t);
304  } else {
305  vector<Model *> mm = t->getOutputModels();
306  for (int i = 0; i < (int)mm.size(); ++i) {
307  if (mm[i] == m) affected.insert(t);
308  }
309  }
310  }
311 
312  for (TransformerSet::iterator i = affected.begin();
313  i != affected.end(); ++i) {
314 
315  ModelTransformer *t = *i;
316 
317  t->abandon();
318 
319  t->wait(); // this should eventually call back on
320  // transformerFinished, which will remove from
321  // m_runningTransformers and delete.
322  }
323 }
324 
void abandon()
Hint to the processing thread that it should give up, for example because the process is going to exi...
Simple interface for audio playback.
virtual Vamp::Plugin * instantiatePlugin(QString identifier, float inputSampleRate)
std::vector< Model * > transformMultiple(const Transforms &transform, const ModelTransformer::Input &input, QString &message, AdditionalModelHandler *handler=0)
Return the multiple output models resulting from applying the named transforms to the given input mod...
virtual void setParametersFromXml(QString xml)
Set the parameters and program of a plugin from an XML plugin element as returned by toXml.
Definition: PluginXml.cpp:194
Model * getModel() const
ModelTransformer * createTransformer(const Transforms &transforms, const ModelTransformer::Input &input)
virtual int getTargetChannelCount() const =0
Get the number of channels of audio that will be provided to the play target.
std::set< ModelTransformer * > TransformerSet
std::vector< Transform > Transforms
Definition: Transform.h:200
static ModelTransformerFactory * getInstance()
QString getMessage() const
Return a warning or error message.
ModelTransformer::Input getConfigurationForTransform(Transform &transform, const std::vector< Model * > &candidateInputModels, Model *defaultInputModel, AudioPlaySource *source=0, int startFrame=0, int duration=0, UserConfigurator *configurator=0)
Fill out the configuration for the given transform (may include asking the user by calling back on th...
static RealTimePluginFactory * instanceFor(QString identifier)
static ModelTransformerFactory * m_instance
void start()
Definition: Thread.cpp:34
Models detachOutputModels()
Return the set of output models, also detaching them from the transformer so that they will not be de...
virtual Models detachAdditionalOutputModels()
Return the set of additional models, also detaching them from the transformer.
QString getTransformFriendlyName(TransformId identifier)
Brief but friendly name of a transform, suitable for use as the name of the output layer.
static TransformFactory * getInstance()
virtual QString toXmlString(QString indent="", QString extraAttributes="") const
Convert this exportable object to XML in a string.
Model * transform(const Transform &transform, const ModelTransformer::Input &input, QString &message, AdditionalModelHandler *handler=0)
Return the output model resulting from applying the named transform to the given input model.
TransformerConfigurationMap m_lastConfigurations
virtual int getSampleRate() const =0
Return the frame rate in frames per second.
Model is the base class for all data models that represent any sort of data on a time scale based on ...
Definition: Model.h:35
virtual bool willHaveAdditionalOutputModels()
Return true if the current transform is one that may produce additional models (to be retrieved throu...
virtual RealTimePluginInstance * instantiatePlugin(QString identifier, int clientId, int position, unsigned int sampleRate, unsigned int blockSize, unsigned int channels)=0
Instantiate a plugin.
#define SVDEBUG
Definition: Debug.h:42
Models getOutputModels()
Return the set of output models created by the transform or transforms.
A ModelTransformer turns one data model into another.
virtual int getTargetSampleRate() const =0
Return the sample rate set by the target audio device (or the source sample rate if the target hasn't...
virtual int getTargetBlockSize() const =0
Get the block size of the target audio device.
Model * getInputModel()
Return the input model for the transform.
virtual bool configure(ModelTransformer::Input &input, Transform &transform, Vamp::PluginBase *plugin, Model *&inputModel, AudioPlaySource *source, int startFrame, int duration, const QMap< QString, Model * > &modelMap, QStringList candidateModelNames, QString defaultModelName)=0
static FeatureExtractionPluginFactory * instanceFor(QString identifier)