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
|