comparison transform/TransformFactory.cpp @ 0:cd5d7ff8ef38

* Reorganising code base. This revision will not compile.
author Chris Cannam
date Mon, 31 Jul 2006 12:03:45 +0000
parents
children 40116f709d3b
comparison
equal deleted inserted replaced
-1:000000000000 0:cd5d7ff8ef38
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.
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
16 #include "TransformFactory.h"
17
18 #include "FeatureExtractionPluginTransform.h"
19 #include "RealTimePluginTransform.h"
20
21 #include "plugin/FeatureExtractionPluginFactory.h"
22 #include "plugin/RealTimePluginFactory.h"
23 #include "plugin/PluginXml.h"
24
25 #include "widgets/PluginParameterDialog.h"
26
27 #include "model/DenseTimeValueModel.h"
28
29 #include <iostream>
30 #include <set>
31
32 #include <QRegExp>
33
34 TransformFactory *
35 TransformFactory::m_instance = new TransformFactory;
36
37 TransformFactory *
38 TransformFactory::getInstance()
39 {
40 return m_instance;
41 }
42
43 TransformFactory::~TransformFactory()
44 {
45 }
46
47 TransformFactory::TransformList
48 TransformFactory::getAllTransforms()
49 {
50 if (m_transforms.empty()) populateTransforms();
51
52 TransformList list;
53 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
54 i != m_transforms.end(); ++i) {
55 list.push_back(i->second);
56 }
57
58 return list;
59 }
60
61 std::vector<QString>
62 TransformFactory::getAllTransformTypes()
63 {
64 if (m_transforms.empty()) populateTransforms();
65
66 std::set<QString> types;
67 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
68 i != m_transforms.end(); ++i) {
69 types.insert(i->second.type);
70 }
71
72 std::vector<QString> rv;
73 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
74 rv.push_back(*i);
75 }
76
77 return rv;
78 }
79
80 void
81 TransformFactory::populateTransforms()
82 {
83 TransformDescriptionMap transforms;
84
85 populateFeatureExtractionPlugins(transforms);
86 populateRealTimePlugins(transforms);
87
88 // disambiguate plugins with similar descriptions
89
90 std::map<QString, int> descriptions;
91
92 for (TransformDescriptionMap::iterator i = transforms.begin();
93 i != transforms.end(); ++i) {
94
95 TransformDesc desc = i->second;
96
97 ++descriptions[desc.description];
98 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
99 }
100
101 std::map<QString, int> counts;
102 m_transforms.clear();
103
104 for (TransformDescriptionMap::iterator i = transforms.begin();
105 i != transforms.end(); ++i) {
106
107 TransformDesc desc = i->second;
108 QString name = desc.name;
109 QString description = desc.description;
110 QString maker = desc.maker;
111
112 if (descriptions[description] > 1) {
113 description = QString("%1 [%2]").arg(description).arg(maker);
114 if (descriptions[description] > 1) {
115 description = QString("%1 <%2>")
116 .arg(description).arg(++counts[description]);
117 }
118 }
119
120 desc.description = description;
121 m_transforms[name] = desc;
122 }
123 }
124
125 void
126 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
127 {
128 std::vector<QString> plugs =
129 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
130
131 for (size_t i = 0; i < plugs.size(); ++i) {
132
133 QString pluginId = plugs[i];
134
135 FeatureExtractionPluginFactory *factory =
136 FeatureExtractionPluginFactory::instanceFor(pluginId);
137
138 if (!factory) {
139 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
140 continue;
141 }
142
143 Vamp::Plugin *plugin =
144 factory->instantiatePlugin(pluginId, 48000);
145
146 if (!plugin) {
147 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
148 continue;
149 }
150
151 QString pluginDescription = plugin->getDescription().c_str();
152 Vamp::Plugin::OutputList outputs =
153 plugin->getOutputDescriptors();
154
155 for (size_t j = 0; j < outputs.size(); ++j) {
156
157 QString transformName = QString("%1:%2")
158 .arg(pluginId).arg(outputs[j].name.c_str());
159
160 QString userDescription;
161 QString friendlyName;
162 QString units = outputs[j].unit.c_str();
163
164 if (outputs.size() == 1) {
165 userDescription = pluginDescription;
166 friendlyName = pluginDescription;
167 } else {
168 userDescription = QString("%1: %2")
169 .arg(pluginDescription)
170 .arg(outputs[j].description.c_str());
171 friendlyName = outputs[j].description.c_str();
172 }
173
174 bool configurable = (!plugin->getPrograms().empty() ||
175 !plugin->getParameterDescriptors().empty());
176
177 transforms[transformName] =
178 TransformDesc(tr("Analysis Plugins"),
179 transformName,
180 userDescription,
181 friendlyName,
182 plugin->getMaker().c_str(),
183 units,
184 configurable);
185 }
186 }
187 }
188
189 void
190 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
191 {
192 std::vector<QString> plugs =
193 RealTimePluginFactory::getAllPluginIdentifiers();
194
195 QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
196
197 for (size_t i = 0; i < plugs.size(); ++i) {
198
199 QString pluginId = plugs[i];
200
201 RealTimePluginFactory *factory =
202 RealTimePluginFactory::instanceFor(pluginId);
203
204 if (!factory) {
205 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
206 continue;
207 }
208
209 const RealTimePluginDescriptor *descriptor =
210 factory->getPluginDescriptor(pluginId);
211
212 if (!descriptor) {
213 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
214 continue;
215 }
216
217 if (descriptor->controlOutputPortCount == 0 ||
218 descriptor->audioInputPortCount == 0) continue;
219
220 // std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
221
222 QString pluginDescription = descriptor->name.c_str();
223
224 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
225
226 QString transformName = QString("%1:%2").arg(pluginId).arg(j);
227 QString userDescription;
228 QString units;
229
230 if (j < descriptor->controlOutputPortNames.size() &&
231 descriptor->controlOutputPortNames[j] != "") {
232
233 QString portName = descriptor->controlOutputPortNames[j].c_str();
234
235 userDescription = tr("%1: %2")
236 .arg(pluginDescription)
237 .arg(portName);
238
239 if (unitRE.indexIn(portName) >= 0) {
240 units = unitRE.cap(1);
241 }
242
243 } else if (descriptor->controlOutputPortCount > 1) {
244
245 userDescription = tr("%1: Output %2")
246 .arg(pluginDescription)
247 .arg(j + 1);
248
249 } else {
250
251 userDescription = pluginDescription;
252 }
253
254
255 bool configurable = (descriptor->parameterCount > 0);
256
257 transforms[transformName] =
258 TransformDesc(tr("Other Plugins"),
259 transformName,
260 userDescription,
261 userDescription,
262 descriptor->maker.c_str(),
263 units,
264 configurable);
265 }
266 }
267 }
268
269 QString
270 TransformFactory::getTransformDescription(TransformName name)
271 {
272 if (m_transforms.find(name) != m_transforms.end()) {
273 return m_transforms[name].description;
274 } else return "";
275 }
276
277 QString
278 TransformFactory::getTransformFriendlyName(TransformName name)
279 {
280 if (m_transforms.find(name) != m_transforms.end()) {
281 return m_transforms[name].friendlyName;
282 } else return "";
283 }
284
285 QString
286 TransformFactory::getTransformUnits(TransformName name)
287 {
288 if (m_transforms.find(name) != m_transforms.end()) {
289 return m_transforms[name].units;
290 } else return "";
291 }
292
293 bool
294 TransformFactory::isTransformConfigurable(TransformName name)
295 {
296 if (m_transforms.find(name) != m_transforms.end()) {
297 return m_transforms[name].configurable;
298 } else return false;
299 }
300
301 bool
302 TransformFactory::getTransformChannelRange(TransformName name,
303 int &min, int &max)
304 {
305 QString id = name.section(':', 0, 2);
306
307 if (FeatureExtractionPluginFactory::instanceFor(id)) {
308
309 Vamp::Plugin *plugin =
310 FeatureExtractionPluginFactory::instanceFor(id)->
311 instantiatePlugin(id, 48000);
312 if (!plugin) return false;
313
314 min = plugin->getMinChannelCount();
315 max = plugin->getMaxChannelCount();
316 delete plugin;
317
318 return true;
319
320 } else if (RealTimePluginFactory::instanceFor(id)) {
321
322 const RealTimePluginDescriptor *descriptor =
323 RealTimePluginFactory::instanceFor(id)->
324 getPluginDescriptor(id);
325 if (!descriptor) return false;
326
327 min = descriptor->audioInputPortCount;
328 max = descriptor->audioInputPortCount;
329
330 return true;
331 }
332
333 return false;
334 }
335
336 bool
337 TransformFactory::getChannelRange(TransformName name, Vamp::PluginBase *plugin,
338 int &minChannels, int &maxChannels)
339 {
340 Vamp::Plugin *vp = 0;
341 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin))) {
342 minChannels = vp->getMinChannelCount();
343 maxChannels = vp->getMaxChannelCount();
344 return true;
345 } else {
346 return getTransformChannelRange(name, minChannels, maxChannels);
347 }
348 }
349
350 bool
351 TransformFactory::getConfigurationForTransform(TransformName name,
352 Model *inputModel,
353 int &channel,
354 QString &configurationXml)
355 {
356 QString id = name.section(':', 0, 2);
357 QString output = name.section(':', 3);
358
359 bool ok = false;
360 configurationXml = m_lastConfigurations[name];
361
362 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
363
364 Vamp::PluginBase *plugin = 0;
365
366 if (FeatureExtractionPluginFactory::instanceFor(id)) {
367
368 plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
369 (id, inputModel->getSampleRate());
370
371 } else if (RealTimePluginFactory::instanceFor(id)) {
372
373 plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
374 (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
375 }
376
377 if (plugin) {
378 if (configurationXml != "") {
379 PluginXml(plugin).setParametersFromXml(configurationXml);
380 }
381
382 int sourceChannels = 1;
383 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
384 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
385 ->getChannelCount();
386 }
387
388 int minChannels = 1, maxChannels = sourceChannels;
389 getChannelRange(name, plugin, minChannels, maxChannels);
390
391 int targetChannels = sourceChannels;
392 if (sourceChannels < minChannels) targetChannels = minChannels;
393 if (sourceChannels > maxChannels) targetChannels = maxChannels;
394
395 int defaultChannel = channel;
396
397 PluginParameterDialog *dialog = new PluginParameterDialog(plugin,
398 sourceChannels,
399 targetChannels,
400 defaultChannel,
401 output);
402 if (dialog->exec() == QDialog::Accepted) {
403 ok = true;
404 }
405 configurationXml = PluginXml(plugin).toXmlString();
406 channel = dialog->getChannel();
407 delete dialog;
408 delete plugin;
409 }
410
411 if (ok) m_lastConfigurations[name] = configurationXml;
412
413 return ok;
414 }
415
416 Transform *
417 TransformFactory::createTransform(TransformName name, Model *inputModel,
418 int channel, QString configurationXml, bool start)
419 {
420 Transform *transform = 0;
421
422 //!!! use channel
423
424 QString id = name.section(':', 0, 2);
425 QString output = name.section(':', 3);
426
427 if (FeatureExtractionPluginFactory::instanceFor(id)) {
428 transform = new FeatureExtractionPluginTransform(inputModel,
429 id,
430 channel,
431 configurationXml,
432 output);
433 } else if (RealTimePluginFactory::instanceFor(id)) {
434 transform = new RealTimePluginTransform(inputModel,
435 id,
436 channel,
437 configurationXml,
438 getTransformUnits(name),
439 output.toInt());
440 } else {
441 std::cerr << "TransformFactory::createTransform: Unknown transform \""
442 << name.toStdString() << "\"" << std::endl;
443 return transform;
444 }
445
446 if (start && transform) transform->start();
447 transform->setObjectName(name);
448 return transform;
449 }
450
451 Model *
452 TransformFactory::transform(TransformName name, Model *inputModel,
453 int channel, QString configurationXml)
454 {
455 Transform *t = createTransform(name, inputModel, channel,
456 configurationXml, false);
457
458 if (!t) return 0;
459
460 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
461
462 t->start();
463 return t->detachOutputModel();
464 }
465
466 void
467 TransformFactory::transformFinished()
468 {
469 QObject *s = sender();
470 Transform *transform = dynamic_cast<Transform *>(s);
471
472 if (!transform) {
473 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
474 return;
475 }
476
477 transform->wait(); // unnecessary but reassuring
478 delete transform;
479 }
480