Mercurial > hg > svcore
comparison plugin/transform/TransformFactory.cpp @ 320:32e50b620a6c
* Move some things around to facilitate plundering libraries for other
applications without needing to duplicate so much code.
sv/osc -> data/osc
sv/audioio -> audioio
sv/transform -> plugin/transform
sv/document -> document (will rename to framework in next commit)
author | Chris Cannam |
---|---|
date | Wed, 24 Oct 2007 16:34:31 +0000 |
parents | |
children | bb6e4c46e202 |
comparison
equal
deleted
inserted
replaced
319:3ff8f571da09 | 320:32e50b620a6c |
---|---|
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 | |
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 "data/model/DenseTimeValueModel.h" | |
28 | |
29 #include "vamp-sdk/PluginHostAdapter.h" | |
30 | |
31 #include "audioio/AudioCallbackPlaySource.h" //!!! shouldn't include here | |
32 | |
33 #include <iostream> | |
34 #include <set> | |
35 | |
36 #include <QRegExp> | |
37 | |
38 TransformFactory * | |
39 TransformFactory::m_instance = new TransformFactory; | |
40 | |
41 TransformFactory * | |
42 TransformFactory::getInstance() | |
43 { | |
44 return m_instance; | |
45 } | |
46 | |
47 TransformFactory::~TransformFactory() | |
48 { | |
49 } | |
50 | |
51 TransformFactory::TransformList | |
52 TransformFactory::getAllTransforms() | |
53 { | |
54 if (m_transforms.empty()) populateTransforms(); | |
55 | |
56 std::set<TransformDesc> dset; | |
57 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); | |
58 i != m_transforms.end(); ++i) { | |
59 dset.insert(i->second); | |
60 } | |
61 | |
62 TransformList list; | |
63 for (std::set<TransformDesc>::const_iterator i = dset.begin(); | |
64 i != dset.end(); ++i) { | |
65 list.push_back(*i); | |
66 } | |
67 | |
68 return list; | |
69 } | |
70 | |
71 std::vector<QString> | |
72 TransformFactory::getAllTransformTypes() | |
73 { | |
74 if (m_transforms.empty()) populateTransforms(); | |
75 | |
76 std::set<QString> types; | |
77 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); | |
78 i != m_transforms.end(); ++i) { | |
79 types.insert(i->second.type); | |
80 } | |
81 | |
82 std::vector<QString> rv; | |
83 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) { | |
84 rv.push_back(*i); | |
85 } | |
86 | |
87 return rv; | |
88 } | |
89 | |
90 std::vector<QString> | |
91 TransformFactory::getTransformCategories(QString transformType) | |
92 { | |
93 if (m_transforms.empty()) populateTransforms(); | |
94 | |
95 std::set<QString> categories; | |
96 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); | |
97 i != m_transforms.end(); ++i) { | |
98 if (i->second.type == transformType) { | |
99 categories.insert(i->second.category); | |
100 } | |
101 } | |
102 | |
103 bool haveEmpty = false; | |
104 | |
105 std::vector<QString> rv; | |
106 for (std::set<QString>::iterator i = categories.begin(); | |
107 i != categories.end(); ++i) { | |
108 if (*i != "") rv.push_back(*i); | |
109 else haveEmpty = true; | |
110 } | |
111 | |
112 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last | |
113 | |
114 return rv; | |
115 } | |
116 | |
117 std::vector<QString> | |
118 TransformFactory::getTransformMakers(QString transformType) | |
119 { | |
120 if (m_transforms.empty()) populateTransforms(); | |
121 | |
122 std::set<QString> makers; | |
123 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); | |
124 i != m_transforms.end(); ++i) { | |
125 if (i->second.type == transformType) { | |
126 makers.insert(i->second.maker); | |
127 } | |
128 } | |
129 | |
130 bool haveEmpty = false; | |
131 | |
132 std::vector<QString> rv; | |
133 for (std::set<QString>::iterator i = makers.begin(); | |
134 i != makers.end(); ++i) { | |
135 if (*i != "") rv.push_back(*i); | |
136 else haveEmpty = true; | |
137 } | |
138 | |
139 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last | |
140 | |
141 return rv; | |
142 } | |
143 | |
144 void | |
145 TransformFactory::populateTransforms() | |
146 { | |
147 TransformDescriptionMap transforms; | |
148 | |
149 populateFeatureExtractionPlugins(transforms); | |
150 populateRealTimePlugins(transforms); | |
151 | |
152 // disambiguate plugins with similar names | |
153 | |
154 std::map<QString, int> names; | |
155 std::map<QString, QString> pluginSources; | |
156 std::map<QString, QString> pluginMakers; | |
157 | |
158 for (TransformDescriptionMap::iterator i = transforms.begin(); | |
159 i != transforms.end(); ++i) { | |
160 | |
161 TransformDesc desc = i->second; | |
162 | |
163 QString td = desc.name; | |
164 QString tn = td.section(": ", 0, 0); | |
165 QString pn = desc.identifier.section(":", 1, 1); | |
166 | |
167 if (pluginSources.find(tn) != pluginSources.end()) { | |
168 if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) { | |
169 ++names[tn]; | |
170 } | |
171 } else { | |
172 ++names[tn]; | |
173 pluginSources[tn] = pn; | |
174 pluginMakers[tn] = desc.maker; | |
175 } | |
176 } | |
177 | |
178 std::map<QString, int> counts; | |
179 m_transforms.clear(); | |
180 | |
181 for (TransformDescriptionMap::iterator i = transforms.begin(); | |
182 i != transforms.end(); ++i) { | |
183 | |
184 TransformDesc desc = i->second; | |
185 QString identifier = desc.identifier; | |
186 QString maker = desc.maker; | |
187 | |
188 QString td = desc.name; | |
189 QString tn = td.section(": ", 0, 0); | |
190 QString to = td.section(": ", 1); | |
191 | |
192 if (names[tn] > 1) { | |
193 maker.replace(QRegExp(tr(" [\\(<].*$")), ""); | |
194 tn = QString("%1 [%2]").arg(tn).arg(maker); | |
195 } | |
196 | |
197 if (to != "") { | |
198 desc.name = QString("%1: %2").arg(tn).arg(to); | |
199 } else { | |
200 desc.name = tn; | |
201 } | |
202 | |
203 m_transforms[identifier] = desc; | |
204 } | |
205 } | |
206 | |
207 void | |
208 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) | |
209 { | |
210 std::vector<QString> plugs = | |
211 FeatureExtractionPluginFactory::getAllPluginIdentifiers(); | |
212 | |
213 for (size_t i = 0; i < plugs.size(); ++i) { | |
214 | |
215 QString pluginId = plugs[i]; | |
216 | |
217 FeatureExtractionPluginFactory *factory = | |
218 FeatureExtractionPluginFactory::instanceFor(pluginId); | |
219 | |
220 if (!factory) { | |
221 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; | |
222 continue; | |
223 } | |
224 | |
225 Vamp::Plugin *plugin = | |
226 factory->instantiatePlugin(pluginId, 48000); | |
227 | |
228 if (!plugin) { | |
229 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; | |
230 continue; | |
231 } | |
232 | |
233 QString pluginName = plugin->getName().c_str(); | |
234 QString category = factory->getPluginCategory(pluginId); | |
235 | |
236 Vamp::Plugin::OutputList outputs = | |
237 plugin->getOutputDescriptors(); | |
238 | |
239 for (size_t j = 0; j < outputs.size(); ++j) { | |
240 | |
241 QString transformId = QString("%1:%2") | |
242 .arg(pluginId).arg(outputs[j].identifier.c_str()); | |
243 | |
244 QString userName; | |
245 QString friendlyName; | |
246 QString units = outputs[j].unit.c_str(); | |
247 QString description = plugin->getDescription().c_str(); | |
248 QString maker = plugin->getMaker().c_str(); | |
249 if (maker == "") maker = tr("<unknown maker>"); | |
250 | |
251 if (description == "") { | |
252 if (outputs.size() == 1) { | |
253 description = tr("Extract features using \"%1\" plugin (from %2)") | |
254 .arg(pluginName).arg(maker); | |
255 } else { | |
256 description = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") | |
257 .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); | |
258 } | |
259 } else { | |
260 if (outputs.size() == 1) { | |
261 description = tr("%1 using \"%2\" plugin (from %3)") | |
262 .arg(description).arg(pluginName).arg(maker); | |
263 } else { | |
264 description = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") | |
265 .arg(description).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); | |
266 } | |
267 } | |
268 | |
269 if (outputs.size() == 1) { | |
270 userName = pluginName; | |
271 friendlyName = pluginName; | |
272 } else { | |
273 userName = QString("%1: %2") | |
274 .arg(pluginName) | |
275 .arg(outputs[j].name.c_str()); | |
276 friendlyName = outputs[j].name.c_str(); | |
277 } | |
278 | |
279 bool configurable = (!plugin->getPrograms().empty() || | |
280 !plugin->getParameterDescriptors().empty()); | |
281 | |
282 // std::cerr << "Feature extraction plugin transform: " << transformId.toStdString() << std::endl; | |
283 | |
284 transforms[transformId] = | |
285 TransformDesc(tr("Analysis"), | |
286 category, | |
287 transformId, | |
288 userName, | |
289 friendlyName, | |
290 description, | |
291 maker, | |
292 units, | |
293 configurable); | |
294 } | |
295 | |
296 delete plugin; | |
297 } | |
298 } | |
299 | |
300 void | |
301 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) | |
302 { | |
303 std::vector<QString> plugs = | |
304 RealTimePluginFactory::getAllPluginIdentifiers(); | |
305 | |
306 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); | |
307 | |
308 for (size_t i = 0; i < plugs.size(); ++i) { | |
309 | |
310 QString pluginId = plugs[i]; | |
311 | |
312 RealTimePluginFactory *factory = | |
313 RealTimePluginFactory::instanceFor(pluginId); | |
314 | |
315 if (!factory) { | |
316 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; | |
317 continue; | |
318 } | |
319 | |
320 const RealTimePluginDescriptor *descriptor = | |
321 factory->getPluginDescriptor(pluginId); | |
322 | |
323 if (!descriptor) { | |
324 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl; | |
325 continue; | |
326 } | |
327 | |
328 //!!! if (descriptor->controlOutputPortCount == 0 || | |
329 // descriptor->audioInputPortCount == 0) continue; | |
330 | |
331 // std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << std::endl; | |
332 | |
333 QString pluginName = descriptor->name.c_str(); | |
334 QString category = factory->getPluginCategory(pluginId); | |
335 bool configurable = (descriptor->parameterCount > 0); | |
336 QString maker = descriptor->maker.c_str(); | |
337 if (maker == "") maker = tr("<unknown maker>"); | |
338 | |
339 if (descriptor->audioInputPortCount > 0) { | |
340 | |
341 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) { | |
342 | |
343 QString transformId = QString("%1:%2").arg(pluginId).arg(j); | |
344 QString userName; | |
345 QString units; | |
346 QString portName; | |
347 | |
348 if (j < descriptor->controlOutputPortNames.size() && | |
349 descriptor->controlOutputPortNames[j] != "") { | |
350 | |
351 portName = descriptor->controlOutputPortNames[j].c_str(); | |
352 | |
353 userName = tr("%1: %2") | |
354 .arg(pluginName) | |
355 .arg(portName); | |
356 | |
357 if (unitRE.indexIn(portName) >= 0) { | |
358 units = unitRE.cap(1); | |
359 } | |
360 | |
361 } else if (descriptor->controlOutputPortCount > 1) { | |
362 | |
363 userName = tr("%1: Output %2") | |
364 .arg(pluginName) | |
365 .arg(j + 1); | |
366 | |
367 } else { | |
368 | |
369 userName = pluginName; | |
370 } | |
371 | |
372 QString description; | |
373 | |
374 if (portName != "") { | |
375 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)") | |
376 .arg(portName) | |
377 .arg(pluginName) | |
378 .arg(maker); | |
379 } else { | |
380 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)") | |
381 .arg(j + 1) | |
382 .arg(pluginName) | |
383 .arg(maker); | |
384 } | |
385 | |
386 transforms[transformId] = | |
387 TransformDesc(tr("Effects Data"), | |
388 category, | |
389 transformId, | |
390 userName, | |
391 userName, | |
392 description, | |
393 maker, | |
394 units, | |
395 configurable); | |
396 } | |
397 } | |
398 | |
399 if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) { | |
400 | |
401 if (descriptor->audioOutputPortCount > 0) { | |
402 | |
403 QString transformId = QString("%1:A").arg(pluginId); | |
404 QString type = tr("Effects"); | |
405 | |
406 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)") | |
407 .arg(pluginName) | |
408 .arg(maker); | |
409 | |
410 if (descriptor->audioInputPortCount == 0) { | |
411 type = tr("Generators"); | |
412 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)") | |
413 .arg(pluginName) | |
414 .arg(maker); | |
415 } | |
416 | |
417 transforms[transformId] = | |
418 TransformDesc(type, | |
419 category, | |
420 transformId, | |
421 pluginName, | |
422 pluginName, | |
423 description, | |
424 maker, | |
425 "", | |
426 configurable); | |
427 } | |
428 } | |
429 } | |
430 } | |
431 | |
432 QString | |
433 TransformFactory::getTransformName(TransformId identifier) | |
434 { | |
435 if (m_transforms.find(identifier) != m_transforms.end()) { | |
436 return m_transforms[identifier].name; | |
437 } else return ""; | |
438 } | |
439 | |
440 QString | |
441 TransformFactory::getTransformFriendlyName(TransformId identifier) | |
442 { | |
443 if (m_transforms.find(identifier) != m_transforms.end()) { | |
444 return m_transforms[identifier].friendlyName; | |
445 } else return ""; | |
446 } | |
447 | |
448 QString | |
449 TransformFactory::getTransformUnits(TransformId identifier) | |
450 { | |
451 if (m_transforms.find(identifier) != m_transforms.end()) { | |
452 return m_transforms[identifier].units; | |
453 } else return ""; | |
454 } | |
455 | |
456 bool | |
457 TransformFactory::isTransformConfigurable(TransformId identifier) | |
458 { | |
459 if (m_transforms.find(identifier) != m_transforms.end()) { | |
460 return m_transforms[identifier].configurable; | |
461 } else return false; | |
462 } | |
463 | |
464 bool | |
465 TransformFactory::getTransformChannelRange(TransformId identifier, | |
466 int &min, int &max) | |
467 { | |
468 QString id = identifier.section(':', 0, 2); | |
469 | |
470 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
471 | |
472 Vamp::Plugin *plugin = | |
473 FeatureExtractionPluginFactory::instanceFor(id)-> | |
474 instantiatePlugin(id, 48000); | |
475 if (!plugin) return false; | |
476 | |
477 min = plugin->getMinChannelCount(); | |
478 max = plugin->getMaxChannelCount(); | |
479 delete plugin; | |
480 | |
481 return true; | |
482 | |
483 } else if (RealTimePluginFactory::instanceFor(id)) { | |
484 | |
485 const RealTimePluginDescriptor *descriptor = | |
486 RealTimePluginFactory::instanceFor(id)-> | |
487 getPluginDescriptor(id); | |
488 if (!descriptor) return false; | |
489 | |
490 min = descriptor->audioInputPortCount; | |
491 max = descriptor->audioInputPortCount; | |
492 | |
493 return true; | |
494 } | |
495 | |
496 return false; | |
497 } | |
498 | |
499 bool | |
500 TransformFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin, | |
501 int &minChannels, int &maxChannels) | |
502 { | |
503 Vamp::Plugin *vp = 0; | |
504 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) || | |
505 (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) { | |
506 minChannels = vp->getMinChannelCount(); | |
507 maxChannels = vp->getMaxChannelCount(); | |
508 return true; | |
509 } else { | |
510 return getTransformChannelRange(identifier, minChannels, maxChannels); | |
511 } | |
512 } | |
513 | |
514 Model * | |
515 TransformFactory::getConfigurationForTransform(TransformId identifier, | |
516 const std::vector<Model *> &candidateInputModels, | |
517 PluginTransform::ExecutionContext &context, | |
518 QString &configurationXml, | |
519 AudioCallbackPlaySource *source, | |
520 size_t startFrame, | |
521 size_t duration) | |
522 { | |
523 if (candidateInputModels.empty()) return 0; | |
524 | |
525 //!!! This will need revision -- we'll have to have a callback | |
526 //from the dialog for when the candidate input model is changed, | |
527 //as we'll need to reinitialise the channel settings in the dialog | |
528 Model *inputModel = candidateInputModels[0]; //!!! for now | |
529 QStringList candidateModelNames; | |
530 std::map<QString, Model *> modelMap; | |
531 for (size_t i = 0; i < candidateInputModels.size(); ++i) { | |
532 QString modelName = candidateInputModels[i]->objectName(); | |
533 QString origModelName = modelName; | |
534 int dupcount = 1; | |
535 while (modelMap.find(modelName) != modelMap.end()) { | |
536 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount); | |
537 } | |
538 modelMap[modelName] = candidateInputModels[i]; | |
539 candidateModelNames.push_back(modelName); | |
540 } | |
541 | |
542 QString id = identifier.section(':', 0, 2); | |
543 QString output = identifier.section(':', 3); | |
544 QString outputLabel = ""; | |
545 QString outputDescription = ""; | |
546 | |
547 bool ok = false; | |
548 configurationXml = m_lastConfigurations[identifier]; | |
549 | |
550 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; | |
551 | |
552 Vamp::PluginBase *plugin = 0; | |
553 | |
554 bool frequency = false; | |
555 bool effect = false; | |
556 bool generator = false; | |
557 | |
558 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
559 | |
560 std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl; | |
561 | |
562 Vamp::Plugin *vp = | |
563 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
564 (id, inputModel->getSampleRate()); | |
565 | |
566 if (vp) { | |
567 | |
568 plugin = vp; | |
569 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain); | |
570 | |
571 std::vector<Vamp::Plugin::OutputDescriptor> od = | |
572 vp->getOutputDescriptors(); | |
573 if (od.size() > 1) { | |
574 for (size_t i = 0; i < od.size(); ++i) { | |
575 if (od[i].identifier == output.toStdString()) { | |
576 outputLabel = od[i].name.c_str(); | |
577 outputDescription = od[i].description.c_str(); | |
578 break; | |
579 } | |
580 } | |
581 } | |
582 } | |
583 | |
584 } else if (RealTimePluginFactory::instanceFor(id)) { | |
585 | |
586 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); | |
587 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id); | |
588 | |
589 if (desc->audioInputPortCount > 0 && | |
590 desc->audioOutputPortCount > 0 && | |
591 !desc->isSynth) { | |
592 effect = true; | |
593 } | |
594 | |
595 if (desc->audioInputPortCount == 0) { | |
596 generator = true; | |
597 } | |
598 | |
599 if (output != "A") { | |
600 int outputNo = output.toInt(); | |
601 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) { | |
602 outputLabel = desc->controlOutputPortNames[outputNo].c_str(); | |
603 } | |
604 } | |
605 | |
606 size_t sampleRate = inputModel->getSampleRate(); | |
607 size_t blockSize = 1024; | |
608 size_t channels = 1; | |
609 if (effect && source) { | |
610 sampleRate = source->getTargetSampleRate(); | |
611 blockSize = source->getTargetBlockSize(); | |
612 channels = source->getTargetChannelCount(); | |
613 } | |
614 | |
615 RealTimePluginInstance *rtp = factory->instantiatePlugin | |
616 (id, 0, 0, sampleRate, blockSize, channels); | |
617 | |
618 plugin = rtp; | |
619 | |
620 if (effect && source && rtp) { | |
621 source->setAuditioningPlugin(rtp); | |
622 } | |
623 } | |
624 | |
625 if (plugin) { | |
626 | |
627 context = PluginTransform::ExecutionContext(context.channel, plugin); | |
628 | |
629 if (configurationXml != "") { | |
630 PluginXml(plugin).setParametersFromXml(configurationXml); | |
631 } | |
632 | |
633 int sourceChannels = 1; | |
634 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) { | |
635 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel) | |
636 ->getChannelCount(); | |
637 } | |
638 | |
639 int minChannels = 1, maxChannels = sourceChannels; | |
640 getChannelRange(identifier, plugin, minChannels, maxChannels); | |
641 | |
642 int targetChannels = sourceChannels; | |
643 if (!effect) { | |
644 if (sourceChannels < minChannels) targetChannels = minChannels; | |
645 if (sourceChannels > maxChannels) targetChannels = maxChannels; | |
646 } | |
647 | |
648 int defaultChannel = context.channel; | |
649 | |
650 PluginParameterDialog *dialog = new PluginParameterDialog(plugin); | |
651 | |
652 if (candidateModelNames.size() > 1 && !generator) { | |
653 dialog->setCandidateInputModels(candidateModelNames); | |
654 } | |
655 | |
656 if (startFrame != 0 || duration != 0) { | |
657 dialog->setShowSelectionOnlyOption(true); | |
658 } | |
659 | |
660 if (targetChannels > 0) { | |
661 dialog->setChannelArrangement(sourceChannels, targetChannels, | |
662 defaultChannel); | |
663 } | |
664 | |
665 dialog->setOutputLabel(outputLabel, outputDescription); | |
666 | |
667 dialog->setShowProcessingOptions(true, frequency); | |
668 | |
669 if (dialog->exec() == QDialog::Accepted) { | |
670 ok = true; | |
671 } | |
672 | |
673 QString selectedInput = dialog->getInputModel(); | |
674 if (selectedInput != "") { | |
675 if (modelMap.find(selectedInput) != modelMap.end()) { | |
676 inputModel = modelMap[selectedInput]; | |
677 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl; | |
678 } else { | |
679 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl; | |
680 } | |
681 } else { | |
682 std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl; | |
683 } | |
684 | |
685 configurationXml = PluginXml(plugin).toXmlString(); | |
686 context.channel = dialog->getChannel(); | |
687 | |
688 if (startFrame != 0 || duration != 0) { | |
689 if (dialog->getSelectionOnly()) { | |
690 context.startFrame = startFrame; | |
691 context.duration = duration; | |
692 } | |
693 } | |
694 | |
695 dialog->getProcessingParameters(context.stepSize, | |
696 context.blockSize, | |
697 context.windowType); | |
698 | |
699 context.makeConsistentWithPlugin(plugin); | |
700 | |
701 delete dialog; | |
702 | |
703 if (effect && source) { | |
704 source->setAuditioningPlugin(0); // will delete our plugin | |
705 } else { | |
706 delete plugin; | |
707 } | |
708 } | |
709 | |
710 if (ok) m_lastConfigurations[identifier] = configurationXml; | |
711 | |
712 return ok ? inputModel : 0; | |
713 } | |
714 | |
715 PluginTransform::ExecutionContext | |
716 TransformFactory::getDefaultContextForTransform(TransformId identifier, | |
717 Model *inputModel) | |
718 { | |
719 PluginTransform::ExecutionContext context(-1); | |
720 | |
721 QString id = identifier.section(':', 0, 2); | |
722 | |
723 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
724 | |
725 Vamp::Plugin *vp = | |
726 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
727 (id, inputModel ? inputModel->getSampleRate() : 48000); | |
728 | |
729 if (vp) { | |
730 context = PluginTransform::ExecutionContext(-1, vp); | |
731 delete vp; | |
732 } | |
733 } | |
734 | |
735 return context; | |
736 } | |
737 | |
738 Transform * | |
739 TransformFactory::createTransform(TransformId identifier, Model *inputModel, | |
740 const PluginTransform::ExecutionContext &context, | |
741 QString configurationXml) | |
742 { | |
743 Transform *transform = 0; | |
744 | |
745 QString id = identifier.section(':', 0, 2); | |
746 QString output = identifier.section(':', 3); | |
747 | |
748 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
749 transform = new FeatureExtractionPluginTransform(inputModel, | |
750 id, | |
751 context, | |
752 configurationXml, | |
753 output); | |
754 } else if (RealTimePluginFactory::instanceFor(id)) { | |
755 transform = new RealTimePluginTransform(inputModel, | |
756 id, | |
757 context, | |
758 configurationXml, | |
759 getTransformUnits(identifier), | |
760 output == "A" ? -1 : | |
761 output.toInt()); | |
762 } else { | |
763 std::cerr << "TransformFactory::createTransform: Unknown transform \"" | |
764 << identifier.toStdString() << "\"" << std::endl; | |
765 return transform; | |
766 } | |
767 | |
768 if (transform) transform->setObjectName(identifier); | |
769 return transform; | |
770 } | |
771 | |
772 Model * | |
773 TransformFactory::transform(TransformId identifier, Model *inputModel, | |
774 const PluginTransform::ExecutionContext &context, | |
775 QString configurationXml) | |
776 { | |
777 Transform *t = createTransform(identifier, inputModel, context, | |
778 configurationXml); | |
779 | |
780 if (!t) return 0; | |
781 | |
782 connect(t, SIGNAL(finished()), this, SLOT(transformFinished())); | |
783 | |
784 m_runningTransforms.insert(t); | |
785 | |
786 t->start(); | |
787 Model *model = t->detachOutputModel(); | |
788 | |
789 if (model) { | |
790 QString imn = inputModel->objectName(); | |
791 QString trn = getTransformFriendlyName(identifier); | |
792 if (imn != "") { | |
793 if (trn != "") { | |
794 model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); | |
795 } else { | |
796 model->setObjectName(imn); | |
797 } | |
798 } else if (trn != "") { | |
799 model->setObjectName(trn); | |
800 } | |
801 } else { | |
802 t->wait(); | |
803 } | |
804 | |
805 return model; | |
806 } | |
807 | |
808 void | |
809 TransformFactory::transformFinished() | |
810 { | |
811 QObject *s = sender(); | |
812 Transform *transform = dynamic_cast<Transform *>(s); | |
813 | |
814 std::cerr << "TransformFactory::transformFinished(" << transform << ")" << std::endl; | |
815 | |
816 if (!transform) { | |
817 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl; | |
818 return; | |
819 } | |
820 | |
821 if (m_runningTransforms.find(transform) == m_runningTransforms.end()) { | |
822 std::cerr << "WARNING: TransformFactory::transformFinished(" | |
823 << transform | |
824 << "): I have no record of this transform running!" | |
825 << std::endl; | |
826 } | |
827 | |
828 m_runningTransforms.erase(transform); | |
829 | |
830 transform->wait(); // unnecessary but reassuring | |
831 delete transform; | |
832 } | |
833 | |
834 void | |
835 TransformFactory::modelAboutToBeDeleted(Model *m) | |
836 { | |
837 TransformSet affected; | |
838 | |
839 for (TransformSet::iterator i = m_runningTransforms.begin(); | |
840 i != m_runningTransforms.end(); ++i) { | |
841 | |
842 Transform *t = *i; | |
843 | |
844 if (t->getInputModel() == m || t->getOutputModel() == m) { | |
845 affected.insert(t); | |
846 } | |
847 } | |
848 | |
849 for (TransformSet::iterator i = affected.begin(); | |
850 i != affected.end(); ++i) { | |
851 | |
852 Transform *t = *i; | |
853 | |
854 t->abandon(); | |
855 | |
856 t->wait(); // this should eventually call back on | |
857 // transformFinished, which will remove from | |
858 // m_runningTransforms and delete. | |
859 } | |
860 } | |
861 |