Mercurial > hg > svcore
comparison plugin/transform/ModelTransformerFactory.cpp @ 331:f620ce48c950
* Further naming change: Transformer -> ModelTransformer.
The Transform class now describes a thing that can be done, and the
ModelTransformer does it to a Model.
author | Chris Cannam |
---|---|
date | Wed, 07 Nov 2007 12:59:01 +0000 |
parents | plugin/transform/TransformerFactory.cpp@3179d8b29336 |
children | 13e5870040e6 |
comparison
equal
deleted
inserted
replaced
330:6e9dcf09b7fe | 331:f620ce48c950 |
---|---|
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 "ModelTransformerFactory.h" | |
17 | |
18 #include "FeatureExtractionModelTransformer.h" | |
19 #include "RealTimeEffectModelTransformer.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 ModelTransformerFactory * | |
39 ModelTransformerFactory::m_instance = new ModelTransformerFactory; | |
40 | |
41 ModelTransformerFactory * | |
42 ModelTransformerFactory::getInstance() | |
43 { | |
44 return m_instance; | |
45 } | |
46 | |
47 ModelTransformerFactory::~ModelTransformerFactory() | |
48 { | |
49 } | |
50 | |
51 TransformList | |
52 ModelTransformerFactory::getAllTransforms() | |
53 { | |
54 if (m_transforms.empty()) populateTransforms(); | |
55 | |
56 std::set<TransformDescription> 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<TransformDescription>::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 ModelTransformerFactory::getAllTransformerTypes() | |
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 ModelTransformerFactory::getTransformerCategories(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 ModelTransformerFactory::getTransformerMakers(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 ModelTransformerFactory::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 TransformDescription 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 TransformDescription 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 ModelTransformerFactory::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: ModelTransformerFactory::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: ModelTransformerFactory::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 TransformDescription(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 ModelTransformerFactory::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: ModelTransformerFactory::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: ModelTransformerFactory::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 << "ModelTransformerFactory::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 TransformDescription(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("Transformer 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 TransformDescription(type, | |
419 category, | |
420 transformId, | |
421 pluginName, | |
422 pluginName, | |
423 description, | |
424 maker, | |
425 "", | |
426 configurable); | |
427 } | |
428 } | |
429 } | |
430 } | |
431 | |
432 bool | |
433 ModelTransformerFactory::haveTransformer(TransformId identifier) | |
434 { | |
435 return (m_transforms.find(identifier) != m_transforms.end()); | |
436 } | |
437 | |
438 QString | |
439 ModelTransformerFactory::getTransformerName(TransformId identifier) | |
440 { | |
441 if (m_transforms.find(identifier) != m_transforms.end()) { | |
442 return m_transforms[identifier].name; | |
443 } else return ""; | |
444 } | |
445 | |
446 QString | |
447 ModelTransformerFactory::getTransformerFriendlyName(TransformId identifier) | |
448 { | |
449 if (m_transforms.find(identifier) != m_transforms.end()) { | |
450 return m_transforms[identifier].friendlyName; | |
451 } else return ""; | |
452 } | |
453 | |
454 QString | |
455 ModelTransformerFactory::getTransformerUnits(TransformId identifier) | |
456 { | |
457 if (m_transforms.find(identifier) != m_transforms.end()) { | |
458 return m_transforms[identifier].units; | |
459 } else return ""; | |
460 } | |
461 | |
462 bool | |
463 ModelTransformerFactory::isTransformerConfigurable(TransformId identifier) | |
464 { | |
465 if (m_transforms.find(identifier) != m_transforms.end()) { | |
466 return m_transforms[identifier].configurable; | |
467 } else return false; | |
468 } | |
469 | |
470 bool | |
471 ModelTransformerFactory::getTransformerChannelRange(TransformId identifier, | |
472 int &min, int &max) | |
473 { | |
474 QString id = identifier.section(':', 0, 2); | |
475 | |
476 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
477 | |
478 Vamp::Plugin *plugin = | |
479 FeatureExtractionPluginFactory::instanceFor(id)-> | |
480 instantiatePlugin(id, 48000); | |
481 if (!plugin) return false; | |
482 | |
483 min = plugin->getMinChannelCount(); | |
484 max = plugin->getMaxChannelCount(); | |
485 delete plugin; | |
486 | |
487 return true; | |
488 | |
489 } else if (RealTimePluginFactory::instanceFor(id)) { | |
490 | |
491 const RealTimePluginDescriptor *descriptor = | |
492 RealTimePluginFactory::instanceFor(id)-> | |
493 getPluginDescriptor(id); | |
494 if (!descriptor) return false; | |
495 | |
496 min = descriptor->audioInputPortCount; | |
497 max = descriptor->audioInputPortCount; | |
498 | |
499 return true; | |
500 } | |
501 | |
502 return false; | |
503 } | |
504 | |
505 bool | |
506 ModelTransformerFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin, | |
507 int &minChannels, int &maxChannels) | |
508 { | |
509 Vamp::Plugin *vp = 0; | |
510 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) || | |
511 (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) { | |
512 minChannels = vp->getMinChannelCount(); | |
513 maxChannels = vp->getMaxChannelCount(); | |
514 return true; | |
515 } else { | |
516 return getTransformerChannelRange(identifier, minChannels, maxChannels); | |
517 } | |
518 } | |
519 | |
520 Model * | |
521 ModelTransformerFactory::getConfigurationForTransformer(TransformId identifier, | |
522 const std::vector<Model *> &candidateInputModels, | |
523 PluginTransformer::ExecutionContext &context, | |
524 QString &configurationXml, | |
525 AudioCallbackPlaySource *source, | |
526 size_t startFrame, | |
527 size_t duration) | |
528 { | |
529 if (candidateInputModels.empty()) return 0; | |
530 | |
531 //!!! This will need revision -- we'll have to have a callback | |
532 //from the dialog for when the candidate input model is changed, | |
533 //as we'll need to reinitialise the channel settings in the dialog | |
534 Model *inputModel = candidateInputModels[0]; //!!! for now | |
535 QStringList candidateModelNames; | |
536 std::map<QString, Model *> modelMap; | |
537 for (size_t i = 0; i < candidateInputModels.size(); ++i) { | |
538 QString modelName = candidateInputModels[i]->objectName(); | |
539 QString origModelName = modelName; | |
540 int dupcount = 1; | |
541 while (modelMap.find(modelName) != modelMap.end()) { | |
542 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount); | |
543 } | |
544 modelMap[modelName] = candidateInputModels[i]; | |
545 candidateModelNames.push_back(modelName); | |
546 } | |
547 | |
548 QString id = identifier.section(':', 0, 2); | |
549 QString output = identifier.section(':', 3); | |
550 QString outputLabel = ""; | |
551 QString outputDescription = ""; | |
552 | |
553 bool ok = false; | |
554 configurationXml = m_lastConfigurations[identifier]; | |
555 | |
556 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; | |
557 | |
558 Vamp::PluginBase *plugin = 0; | |
559 | |
560 bool frequency = false; | |
561 bool effect = false; | |
562 bool generator = false; | |
563 | |
564 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
565 | |
566 std::cerr << "getConfigurationForTransformer: instantiating Vamp plugin" << std::endl; | |
567 | |
568 Vamp::Plugin *vp = | |
569 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
570 (id, inputModel->getSampleRate()); | |
571 | |
572 if (vp) { | |
573 | |
574 plugin = vp; | |
575 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain); | |
576 | |
577 std::vector<Vamp::Plugin::OutputDescriptor> od = | |
578 vp->getOutputDescriptors(); | |
579 if (od.size() > 1) { | |
580 for (size_t i = 0; i < od.size(); ++i) { | |
581 if (od[i].identifier == output.toStdString()) { | |
582 outputLabel = od[i].name.c_str(); | |
583 outputDescription = od[i].description.c_str(); | |
584 break; | |
585 } | |
586 } | |
587 } | |
588 } | |
589 | |
590 } else if (RealTimePluginFactory::instanceFor(id)) { | |
591 | |
592 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); | |
593 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id); | |
594 | |
595 if (desc->audioInputPortCount > 0 && | |
596 desc->audioOutputPortCount > 0 && | |
597 !desc->isSynth) { | |
598 effect = true; | |
599 } | |
600 | |
601 if (desc->audioInputPortCount == 0) { | |
602 generator = true; | |
603 } | |
604 | |
605 if (output != "A") { | |
606 int outputNo = output.toInt(); | |
607 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) { | |
608 outputLabel = desc->controlOutputPortNames[outputNo].c_str(); | |
609 } | |
610 } | |
611 | |
612 size_t sampleRate = inputModel->getSampleRate(); | |
613 size_t blockSize = 1024; | |
614 size_t channels = 1; | |
615 if (effect && source) { | |
616 sampleRate = source->getTargetSampleRate(); | |
617 blockSize = source->getTargetBlockSize(); | |
618 channels = source->getTargetChannelCount(); | |
619 } | |
620 | |
621 RealTimePluginInstance *rtp = factory->instantiatePlugin | |
622 (id, 0, 0, sampleRate, blockSize, channels); | |
623 | |
624 plugin = rtp; | |
625 | |
626 if (effect && source && rtp) { | |
627 source->setAuditioningPlugin(rtp); | |
628 } | |
629 } | |
630 | |
631 if (plugin) { | |
632 | |
633 context = PluginTransformer::ExecutionContext(context.channel, plugin); | |
634 | |
635 if (configurationXml != "") { | |
636 PluginXml(plugin).setParametersFromXml(configurationXml); | |
637 } | |
638 | |
639 int sourceChannels = 1; | |
640 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) { | |
641 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel) | |
642 ->getChannelCount(); | |
643 } | |
644 | |
645 int minChannels = 1, maxChannels = sourceChannels; | |
646 getChannelRange(identifier, plugin, minChannels, maxChannels); | |
647 | |
648 int targetChannels = sourceChannels; | |
649 if (!effect) { | |
650 if (sourceChannels < minChannels) targetChannels = minChannels; | |
651 if (sourceChannels > maxChannels) targetChannels = maxChannels; | |
652 } | |
653 | |
654 int defaultChannel = context.channel; | |
655 | |
656 PluginParameterDialog *dialog = new PluginParameterDialog(plugin); | |
657 | |
658 if (candidateModelNames.size() > 1 && !generator) { | |
659 dialog->setCandidateInputModels(candidateModelNames); | |
660 } | |
661 | |
662 if (startFrame != 0 || duration != 0) { | |
663 dialog->setShowSelectionOnlyOption(true); | |
664 } | |
665 | |
666 if (targetChannels > 0) { | |
667 dialog->setChannelArrangement(sourceChannels, targetChannels, | |
668 defaultChannel); | |
669 } | |
670 | |
671 dialog->setOutputLabel(outputLabel, outputDescription); | |
672 | |
673 dialog->setShowProcessingOptions(true, frequency); | |
674 | |
675 if (dialog->exec() == QDialog::Accepted) { | |
676 ok = true; | |
677 } | |
678 | |
679 QString selectedInput = dialog->getInputModel(); | |
680 if (selectedInput != "") { | |
681 if (modelMap.find(selectedInput) != modelMap.end()) { | |
682 inputModel = modelMap[selectedInput]; | |
683 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl; | |
684 } else { | |
685 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl; | |
686 } | |
687 } else { | |
688 std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl; | |
689 } | |
690 | |
691 configurationXml = PluginXml(plugin).toXmlString(); | |
692 context.channel = dialog->getChannel(); | |
693 | |
694 if (startFrame != 0 || duration != 0) { | |
695 if (dialog->getSelectionOnly()) { | |
696 context.startFrame = startFrame; | |
697 context.duration = duration; | |
698 } | |
699 } | |
700 | |
701 dialog->getProcessingParameters(context.stepSize, | |
702 context.blockSize, | |
703 context.windowType); | |
704 | |
705 context.makeConsistentWithPlugin(plugin); | |
706 | |
707 delete dialog; | |
708 | |
709 if (effect && source) { | |
710 source->setAuditioningPlugin(0); // will delete our plugin | |
711 } else { | |
712 delete plugin; | |
713 } | |
714 } | |
715 | |
716 if (ok) m_lastConfigurations[identifier] = configurationXml; | |
717 | |
718 return ok ? inputModel : 0; | |
719 } | |
720 | |
721 PluginTransformer::ExecutionContext | |
722 ModelTransformerFactory::getDefaultContextForTransformer(TransformId identifier, | |
723 Model *inputModel) | |
724 { | |
725 PluginTransformer::ExecutionContext context(-1); | |
726 | |
727 QString id = identifier.section(':', 0, 2); | |
728 | |
729 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
730 | |
731 Vamp::Plugin *vp = | |
732 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
733 (id, inputModel ? inputModel->getSampleRate() : 48000); | |
734 | |
735 if (vp) { | |
736 context = PluginTransformer::ExecutionContext(-1, vp); | |
737 delete vp; | |
738 } | |
739 } | |
740 | |
741 return context; | |
742 } | |
743 | |
744 ModelTransformer * | |
745 ModelTransformerFactory::createTransformer(TransformId identifier, Model *inputModel, | |
746 const PluginTransformer::ExecutionContext &context, | |
747 QString configurationXml) | |
748 { | |
749 ModelTransformer *transformer = 0; | |
750 | |
751 QString id = identifier.section(':', 0, 2); | |
752 QString output = identifier.section(':', 3); | |
753 | |
754 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
755 transformer = new FeatureExtractionModelTransformer(inputModel, | |
756 id, | |
757 context, | |
758 configurationXml, | |
759 output); | |
760 } else if (RealTimePluginFactory::instanceFor(id)) { | |
761 transformer = new RealTimeEffectModelTransformer(inputModel, | |
762 id, | |
763 context, | |
764 configurationXml, | |
765 getTransformerUnits(identifier), | |
766 output == "A" ? -1 : | |
767 output.toInt()); | |
768 } else { | |
769 std::cerr << "ModelTransformerFactory::createTransformer: Unknown transform \"" | |
770 << identifier.toStdString() << "\"" << std::endl; | |
771 return transformer; | |
772 } | |
773 | |
774 if (transformer) transformer->setObjectName(identifier); | |
775 return transformer; | |
776 } | |
777 | |
778 Model * | |
779 ModelTransformerFactory::transform(TransformId identifier, Model *inputModel, | |
780 const PluginTransformer::ExecutionContext &context, | |
781 QString configurationXml) | |
782 { | |
783 ModelTransformer *t = createTransformer(identifier, inputModel, context, | |
784 configurationXml); | |
785 | |
786 if (!t) return 0; | |
787 | |
788 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished())); | |
789 | |
790 m_runningTransformers.insert(t); | |
791 | |
792 t->start(); | |
793 Model *model = t->detachOutputModel(); | |
794 | |
795 if (model) { | |
796 QString imn = inputModel->objectName(); | |
797 QString trn = getTransformerFriendlyName(identifier); | |
798 if (imn != "") { | |
799 if (trn != "") { | |
800 model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); | |
801 } else { | |
802 model->setObjectName(imn); | |
803 } | |
804 } else if (trn != "") { | |
805 model->setObjectName(trn); | |
806 } | |
807 } else { | |
808 t->wait(); | |
809 } | |
810 | |
811 return model; | |
812 } | |
813 | |
814 void | |
815 ModelTransformerFactory::transformerFinished() | |
816 { | |
817 QObject *s = sender(); | |
818 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s); | |
819 | |
820 std::cerr << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << std::endl; | |
821 | |
822 if (!transformer) { | |
823 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << std::endl; | |
824 return; | |
825 } | |
826 | |
827 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) { | |
828 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished(" | |
829 << transformer | |
830 << "): I have no record of this transformer running!" | |
831 << std::endl; | |
832 } | |
833 | |
834 m_runningTransformers.erase(transformer); | |
835 | |
836 transformer->wait(); // unnecessary but reassuring | |
837 delete transformer; | |
838 } | |
839 | |
840 void | |
841 ModelTransformerFactory::modelAboutToBeDeleted(Model *m) | |
842 { | |
843 TransformerSet affected; | |
844 | |
845 for (TransformerSet::iterator i = m_runningTransformers.begin(); | |
846 i != m_runningTransformers.end(); ++i) { | |
847 | |
848 ModelTransformer *t = *i; | |
849 | |
850 if (t->getInputModel() == m || t->getOutputModel() == m) { | |
851 affected.insert(t); | |
852 } | |
853 } | |
854 | |
855 for (TransformerSet::iterator i = affected.begin(); | |
856 i != affected.end(); ++i) { | |
857 | |
858 ModelTransformer *t = *i; | |
859 | |
860 t->abandon(); | |
861 | |
862 t->wait(); // this should eventually call back on | |
863 // transformerFinished, which will remove from | |
864 // m_runningTransformers and delete. | |
865 } | |
866 } | |
867 |