Mercurial > hg > sonic-visualiser
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 |