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@331
|
38 ModelTransformerFactory *
|
Chris@331
|
39 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
|
Chris@320
|
40
|
Chris@331
|
41 ModelTransformerFactory *
|
Chris@331
|
42 ModelTransformerFactory::getInstance()
|
Chris@320
|
43 {
|
Chris@320
|
44 return m_instance;
|
Chris@320
|
45 }
|
Chris@320
|
46
|
Chris@331
|
47 ModelTransformerFactory::~ModelTransformerFactory()
|
Chris@320
|
48 {
|
Chris@320
|
49 }
|
Chris@320
|
50
|
Chris@350
|
51 ModelTransformer::Input
|
Chris@350
|
52 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
|
Chris@350
|
53 const std::vector<Model *> &candidateInputModels,
|
Chris@350
|
54 Model *defaultInputModel,
|
Chris@389
|
55 AudioPlaySource *source,
|
Chris@350
|
56 size_t startFrame,
|
Chris@653
|
57 size_t duration,
|
Chris@653
|
58 UserConfigurator *configurator)
|
Chris@320
|
59 {
|
Chris@350
|
60 ModelTransformer::Input input(0);
|
Chris@350
|
61
|
Chris@350
|
62 if (candidateInputModels.empty()) return input;
|
Chris@320
|
63
|
Chris@320
|
64 //!!! This will need revision -- we'll have to have a callback
|
Chris@320
|
65 //from the dialog for when the candidate input model is changed,
|
Chris@320
|
66 //as we'll need to reinitialise the channel settings in the dialog
|
Chris@345
|
67 Model *inputModel = candidateInputModels[0];
|
Chris@320
|
68 QStringList candidateModelNames;
|
Chris@345
|
69 QString defaultModelName;
|
Chris@653
|
70 QMap<QString, Model *> modelMap;
|
Chris@320
|
71 for (size_t i = 0; i < candidateInputModels.size(); ++i) {
|
Chris@320
|
72 QString modelName = candidateInputModels[i]->objectName();
|
Chris@320
|
73 QString origModelName = modelName;
|
Chris@320
|
74 int dupcount = 1;
|
Chris@653
|
75 while (modelMap.contains(modelName)) {
|
Chris@320
|
76 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
|
Chris@320
|
77 }
|
Chris@320
|
78 modelMap[modelName] = candidateInputModels[i];
|
Chris@320
|
79 candidateModelNames.push_back(modelName);
|
Chris@345
|
80 if (candidateInputModels[i] == defaultInputModel) {
|
Chris@345
|
81 defaultModelName = modelName;
|
Chris@345
|
82 }
|
Chris@320
|
83 }
|
Chris@320
|
84
|
Chris@350
|
85 QString id = transform.getPluginIdentifier();
|
Chris@320
|
86
|
Chris@653
|
87 bool ok = true;
|
Chris@350
|
88 QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
|
Chris@320
|
89
|
Chris@686
|
90 std::cerr << "last configuration: " << configurationXml << std::endl;
|
Chris@320
|
91
|
Chris@320
|
92 Vamp::PluginBase *plugin = 0;
|
Chris@320
|
93
|
Chris@320
|
94 if (FeatureExtractionPluginFactory::instanceFor(id)) {
|
Chris@320
|
95
|
Chris@350
|
96 std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl;
|
Chris@320
|
97
|
Chris@320
|
98 Vamp::Plugin *vp =
|
Chris@320
|
99 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
|
Chris@320
|
100 (id, inputModel->getSampleRate());
|
Chris@320
|
101
|
Chris@653
|
102 plugin = vp;
|
Chris@320
|
103
|
Chris@320
|
104 } else if (RealTimePluginFactory::instanceFor(id)) {
|
Chris@320
|
105
|
Chris@320
|
106 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
|
Chris@320
|
107 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
|
Chris@320
|
108
|
Chris@320
|
109 size_t sampleRate = inputModel->getSampleRate();
|
Chris@320
|
110 size_t blockSize = 1024;
|
Chris@320
|
111 size_t channels = 1;
|
Chris@653
|
112 if (source) {
|
Chris@320
|
113 sampleRate = source->getTargetSampleRate();
|
Chris@320
|
114 blockSize = source->getTargetBlockSize();
|
Chris@320
|
115 channels = source->getTargetChannelCount();
|
Chris@320
|
116 }
|
Chris@320
|
117
|
Chris@320
|
118 RealTimePluginInstance *rtp = factory->instantiatePlugin
|
Chris@320
|
119 (id, 0, 0, sampleRate, blockSize, channels);
|
Chris@320
|
120
|
Chris@320
|
121 plugin = rtp;
|
Chris@320
|
122 }
|
Chris@320
|
123
|
Chris@320
|
124 if (plugin) {
|
Chris@320
|
125
|
Chris@350
|
126 // Ensure block size etc are valid
|
Chris@350
|
127 TransformFactory::getInstance()->
|
Chris@350
|
128 makeContextConsistentWithPlugin(transform, plugin);
|
Chris@320
|
129
|
Chris@350
|
130 // Prepare the plugin with any existing parameters already
|
Chris@350
|
131 // found in the transform
|
Chris@350
|
132 TransformFactory::getInstance()->
|
Chris@350
|
133 setPluginParameters(transform, plugin);
|
Chris@350
|
134
|
Chris@350
|
135 // For this interactive usage, we want to override those with
|
Chris@350
|
136 // whatever the user chose last time around
|
Chris@350
|
137 PluginXml(plugin).setParametersFromXml(configurationXml);
|
Chris@320
|
138
|
Chris@653
|
139 if (configurator) {
|
Chris@653
|
140 ok = configurator->configure(input, transform, plugin,
|
Chris@653
|
141 inputModel, source,
|
Chris@653
|
142 startFrame, duration,
|
Chris@653
|
143 modelMap,
|
Chris@653
|
144 candidateModelNames,
|
Chris@653
|
145 defaultModelName);
|
Chris@320
|
146 }
|
Chris@320
|
147
|
Chris@516
|
148
|
Chris@350
|
149 TransformFactory::getInstance()->
|
Chris@350
|
150 makeContextConsistentWithPlugin(transform, plugin);
|
Chris@350
|
151
|
Chris@350
|
152 configurationXml = PluginXml(plugin).toXmlString();
|
Chris@320
|
153
|
Chris@653
|
154 delete plugin;
|
Chris@320
|
155 }
|
Chris@320
|
156
|
Chris@350
|
157 if (ok) {
|
Chris@350
|
158 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
|
Chris@350
|
159 input.setModel(inputModel);
|
Chris@350
|
160 }
|
Chris@320
|
161
|
Chris@350
|
162 return input;
|
Chris@320
|
163 }
|
Chris@320
|
164
|
Chris@331
|
165 ModelTransformer *
|
Chris@350
|
166 ModelTransformerFactory::createTransformer(const Transform &transform,
|
Chris@350
|
167 const ModelTransformer::Input &input)
|
Chris@320
|
168 {
|
Chris@331
|
169 ModelTransformer *transformer = 0;
|
Chris@320
|
170
|
Chris@350
|
171 QString id = transform.getPluginIdentifier();
|
Chris@320
|
172
|
Chris@320
|
173 if (FeatureExtractionPluginFactory::instanceFor(id)) {
|
Chris@350
|
174
|
Chris@350
|
175 transformer =
|
gyorgyf@786
|
176 new FeatureExtractionModelTransformer(input, transform, m_preferredOutputModel);
|
Chris@350
|
177
|
Chris@331
|
178 } else if (RealTimePluginFactory::instanceFor(id)) {
|
Chris@350
|
179
|
Chris@350
|
180 transformer =
|
Chris@350
|
181 new RealTimeEffectModelTransformer(input, transform);
|
Chris@350
|
182
|
Chris@320
|
183 } else {
|
Chris@690
|
184 SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \""
|
Chris@687
|
185 << transform.getIdentifier() << "\"" << endl;
|
Chris@331
|
186 return transformer;
|
Chris@320
|
187 }
|
Chris@320
|
188
|
Chris@350
|
189 if (transformer) transformer->setObjectName(transform.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,
|
gyorgyf@786
|
196 QString &message,
|
gyorgyf@787
|
197 /* outputmodel default value = FeatureExtractionModelTransformer::NoteOutputModel */
|
gyorgyf@786
|
198 FeatureExtractionModelTransformer::PreferredOutputModel outputmodel)
|
Chris@320
|
199 {
|
Chris@690
|
200 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
|
Chris@408
|
201
|
gyorgyf@786
|
202 m_preferredOutputModel = outputmodel;
|
Chris@350
|
203 ModelTransformer *t = createTransformer(transform, input);
|
Chris@320
|
204 if (!t) return 0;
|
Chris@320
|
205
|
Chris@331
|
206 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
|
Chris@320
|
207
|
Chris@328
|
208 m_runningTransformers.insert(t);
|
Chris@320
|
209
|
Chris@320
|
210 t->start();
|
Chris@320
|
211 Model *model = t->detachOutputModel();
|
Chris@320
|
212
|
Chris@320
|
213 if (model) {
|
Chris@350
|
214 QString imn = input.getModel()->objectName();
|
Chris@332
|
215 QString trn =
|
Chris@332
|
216 TransformFactory::getInstance()->getTransformFriendlyName
|
Chris@350
|
217 (transform.getIdentifier());
|
Chris@320
|
218 if (imn != "") {
|
Chris@320
|
219 if (trn != "") {
|
Chris@320
|
220 model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
|
Chris@320
|
221 } else {
|
Chris@320
|
222 model->setObjectName(imn);
|
Chris@320
|
223 }
|
Chris@320
|
224 } else if (trn != "") {
|
Chris@320
|
225 model->setObjectName(trn);
|
Chris@320
|
226 }
|
Chris@320
|
227 } else {
|
Chris@320
|
228 t->wait();
|
Chris@320
|
229 }
|
Chris@320
|
230
|
Chris@361
|
231 message = t->getMessage();
|
Chris@361
|
232
|
Chris@320
|
233 return model;
|
Chris@320
|
234 }
|
Chris@320
|
235
|
Chris@320
|
236 void
|
Chris@331
|
237 ModelTransformerFactory::transformerFinished()
|
Chris@320
|
238 {
|
Chris@320
|
239 QObject *s = sender();
|
Chris@331
|
240 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
|
Chris@320
|
241
|
Chris@690
|
242 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
|
Chris@320
|
243
|
Chris@331
|
244 if (!transformer) {
|
Chris@331
|
245 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << std::endl;
|
Chris@320
|
246 return;
|
Chris@320
|
247 }
|
Chris@320
|
248
|
Chris@331
|
249 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
|
Chris@331
|
250 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished("
|
Chris@331
|
251 << transformer
|
Chris@331
|
252 << "): I have no record of this transformer running!"
|
Chris@320
|
253 << std::endl;
|
Chris@320
|
254 }
|
Chris@320
|
255
|
Chris@331
|
256 m_runningTransformers.erase(transformer);
|
Chris@320
|
257
|
Chris@331
|
258 transformer->wait(); // unnecessary but reassuring
|
Chris@331
|
259 delete transformer;
|
Chris@320
|
260 }
|
Chris@320
|
261
|
Chris@320
|
262 void
|
Chris@331
|
263 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
|
Chris@320
|
264 {
|
Chris@328
|
265 TransformerSet affected;
|
Chris@320
|
266
|
Chris@328
|
267 for (TransformerSet::iterator i = m_runningTransformers.begin();
|
Chris@328
|
268 i != m_runningTransformers.end(); ++i) {
|
Chris@320
|
269
|
Chris@331
|
270 ModelTransformer *t = *i;
|
Chris@320
|
271
|
Chris@320
|
272 if (t->getInputModel() == m || t->getOutputModel() == m) {
|
Chris@320
|
273 affected.insert(t);
|
Chris@320
|
274 }
|
Chris@320
|
275 }
|
Chris@320
|
276
|
Chris@328
|
277 for (TransformerSet::iterator i = affected.begin();
|
Chris@320
|
278 i != affected.end(); ++i) {
|
Chris@320
|
279
|
Chris@331
|
280 ModelTransformer *t = *i;
|
Chris@320
|
281
|
Chris@320
|
282 t->abandon();
|
Chris@320
|
283
|
Chris@320
|
284 t->wait(); // this should eventually call back on
|
Chris@331
|
285 // transformerFinished, which will remove from
|
Chris@328
|
286 // m_runningTransformers and delete.
|
Chris@320
|
287 }
|
Chris@320
|
288 }
|
Chris@320
|
289
|