Mercurial > hg > easaier-soundaccess
comparison sv/transform/TransformFactory.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
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 "sv/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 } | |
297 | |
298 void | |
299 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) | |
300 { | |
301 std::vector<QString> plugs = | |
302 RealTimePluginFactory::getAllPluginIdentifiers(); | |
303 | |
304 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); | |
305 | |
306 for (size_t i = 0; i < plugs.size(); ++i) { | |
307 | |
308 QString pluginId = plugs[i]; | |
309 | |
310 RealTimePluginFactory *factory = | |
311 RealTimePluginFactory::instanceFor(pluginId); | |
312 | |
313 if (!factory) { | |
314 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; | |
315 continue; | |
316 } | |
317 | |
318 const RealTimePluginDescriptor *descriptor = | |
319 factory->getPluginDescriptor(pluginId); | |
320 | |
321 if (!descriptor) { | |
322 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl; | |
323 continue; | |
324 } | |
325 | |
326 //!!! if (descriptor->controlOutputPortCount == 0 || | |
327 // descriptor->audioInputPortCount == 0) continue; | |
328 | |
329 // std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << std::endl; | |
330 | |
331 QString pluginName = descriptor->name.c_str(); | |
332 QString category = factory->getPluginCategory(pluginId); | |
333 bool configurable = (descriptor->parameterCount > 0); | |
334 QString maker = descriptor->maker.c_str(); | |
335 if (maker == "") maker = tr("<unknown maker>"); | |
336 | |
337 if (descriptor->audioInputPortCount > 0) { | |
338 | |
339 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) { | |
340 | |
341 QString transformId = QString("%1:%2").arg(pluginId).arg(j); | |
342 QString userName; | |
343 QString units; | |
344 QString portName; | |
345 | |
346 if (j < descriptor->controlOutputPortNames.size() && | |
347 descriptor->controlOutputPortNames[j] != "") { | |
348 | |
349 portName = descriptor->controlOutputPortNames[j].c_str(); | |
350 | |
351 userName = tr("%1: %2") | |
352 .arg(pluginName) | |
353 .arg(portName); | |
354 | |
355 if (unitRE.indexIn(portName) >= 0) { | |
356 units = unitRE.cap(1); | |
357 } | |
358 | |
359 } else if (descriptor->controlOutputPortCount > 1) { | |
360 | |
361 userName = tr("%1: Output %2") | |
362 .arg(pluginName) | |
363 .arg(j + 1); | |
364 | |
365 } else { | |
366 | |
367 userName = pluginName; | |
368 } | |
369 | |
370 QString description; | |
371 | |
372 if (portName != "") { | |
373 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)") | |
374 .arg(portName) | |
375 .arg(pluginName) | |
376 .arg(maker); | |
377 } else { | |
378 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)") | |
379 .arg(j + 1) | |
380 .arg(pluginName) | |
381 .arg(maker); | |
382 } | |
383 | |
384 transforms[transformId] = | |
385 TransformDesc(tr("Effects Data"), | |
386 category, | |
387 transformId, | |
388 userName, | |
389 userName, | |
390 description, | |
391 maker, | |
392 units, | |
393 configurable); | |
394 } | |
395 } | |
396 | |
397 if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) { | |
398 | |
399 if (descriptor->audioOutputPortCount > 0) { | |
400 | |
401 QString transformId = QString("%1:A").arg(pluginId); | |
402 QString type = tr("Effects"); | |
403 | |
404 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)") | |
405 .arg(pluginName) | |
406 .arg(maker); | |
407 | |
408 if (descriptor->audioInputPortCount == 0) { | |
409 type = tr("Generators"); | |
410 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)") | |
411 .arg(pluginName) | |
412 .arg(maker); | |
413 } | |
414 | |
415 transforms[transformId] = | |
416 TransformDesc(type, | |
417 category, | |
418 transformId, | |
419 pluginName, | |
420 pluginName, | |
421 description, | |
422 maker, | |
423 "", | |
424 configurable); | |
425 } | |
426 } | |
427 } | |
428 } | |
429 | |
430 QString | |
431 TransformFactory::getTransformName(TransformId identifier) | |
432 { | |
433 if (m_transforms.find(identifier) != m_transforms.end()) { | |
434 return m_transforms[identifier].name; | |
435 } else return ""; | |
436 } | |
437 | |
438 QString | |
439 TransformFactory::getTransformFriendlyName(TransformId identifier) | |
440 { | |
441 if (m_transforms.find(identifier) != m_transforms.end()) { | |
442 return m_transforms[identifier].friendlyName; | |
443 } else return ""; | |
444 } | |
445 | |
446 QString | |
447 TransformFactory::getTransformUnits(TransformId identifier) | |
448 { | |
449 if (m_transforms.find(identifier) != m_transforms.end()) { | |
450 return m_transforms[identifier].units; | |
451 } else return ""; | |
452 } | |
453 | |
454 bool | |
455 TransformFactory::isTransformConfigurable(TransformId identifier) | |
456 { | |
457 if (m_transforms.find(identifier) != m_transforms.end()) { | |
458 return m_transforms[identifier].configurable; | |
459 } else return false; | |
460 } | |
461 | |
462 bool | |
463 TransformFactory::getTransformChannelRange(TransformId identifier, | |
464 int &min, int &max) | |
465 { | |
466 QString id = identifier.section(':', 0, 2); | |
467 | |
468 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
469 | |
470 Vamp::Plugin *plugin = | |
471 FeatureExtractionPluginFactory::instanceFor(id)-> | |
472 instantiatePlugin(id, 48000); | |
473 if (!plugin) return false; | |
474 | |
475 min = plugin->getMinChannelCount(); | |
476 max = plugin->getMaxChannelCount(); | |
477 delete plugin; | |
478 | |
479 return true; | |
480 | |
481 } else if (RealTimePluginFactory::instanceFor(id)) { | |
482 | |
483 const RealTimePluginDescriptor *descriptor = | |
484 RealTimePluginFactory::instanceFor(id)-> | |
485 getPluginDescriptor(id); | |
486 if (!descriptor) return false; | |
487 | |
488 min = descriptor->audioInputPortCount; | |
489 max = descriptor->audioInputPortCount; | |
490 | |
491 return true; | |
492 } | |
493 | |
494 return false; | |
495 } | |
496 | |
497 bool | |
498 TransformFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin, | |
499 int &minChannels, int &maxChannels) | |
500 { | |
501 Vamp::Plugin *vp = 0; | |
502 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) || | |
503 (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) { | |
504 minChannels = vp->getMinChannelCount(); | |
505 maxChannels = vp->getMaxChannelCount(); | |
506 return true; | |
507 } else { | |
508 return getTransformChannelRange(identifier, minChannels, maxChannels); | |
509 } | |
510 } | |
511 | |
512 Model * | |
513 TransformFactory::getConfigurationForTransform(TransformId identifier, | |
514 const std::vector<Model *> &candidateInputModels, | |
515 PluginTransform::ExecutionContext &context, | |
516 QString &configurationXml, | |
517 AudioCallbackPlaySource *source) | |
518 { | |
519 if (candidateInputModels.empty()) return 0; | |
520 | |
521 //!!! This will need revision -- we'll have to have a callback | |
522 //from the dialog for when the candidate input model is changed, | |
523 //as we'll need to reinitialise the channel settings in the dialog | |
524 Model *inputModel = candidateInputModels[0]; //!!! for now | |
525 QStringList candidateModelNames; | |
526 std::map<QString, Model *> modelMap; | |
527 for (size_t i = 0; i < candidateInputModels.size(); ++i) { | |
528 QString modelName = candidateInputModels[i]->objectName(); | |
529 QString origModelName = modelName; | |
530 int dupcount = 1; | |
531 while (modelMap.find(modelName) != modelMap.end()) { | |
532 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount); | |
533 } | |
534 modelMap[modelName] = candidateInputModels[i]; | |
535 candidateModelNames.push_back(modelName); | |
536 } | |
537 | |
538 QString id = identifier.section(':', 0, 2); | |
539 QString output = identifier.section(':', 3); | |
540 QString outputLabel = ""; | |
541 QString outputDescription = ""; | |
542 | |
543 bool ok = false; | |
544 configurationXml = m_lastConfigurations[identifier]; | |
545 | |
546 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; | |
547 | |
548 Vamp::PluginBase *plugin = 0; | |
549 | |
550 bool frequency = false; | |
551 bool effect = false; | |
552 bool generator = false; | |
553 | |
554 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
555 | |
556 Vamp::Plugin *vp = | |
557 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
558 (id, inputModel->getSampleRate()); | |
559 | |
560 if (vp) { | |
561 | |
562 plugin = vp; | |
563 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain); | |
564 | |
565 std::vector<Vamp::Plugin::OutputDescriptor> od = | |
566 vp->getOutputDescriptors(); | |
567 if (od.size() > 1) { | |
568 for (size_t i = 0; i < od.size(); ++i) { | |
569 if (od[i].identifier == output.toStdString()) { | |
570 outputLabel = od[i].name.c_str(); | |
571 outputDescription = od[i].description.c_str(); | |
572 break; | |
573 } | |
574 } | |
575 } | |
576 } | |
577 | |
578 } else if (RealTimePluginFactory::instanceFor(id)) { | |
579 | |
580 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); | |
581 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id); | |
582 | |
583 if (desc->audioInputPortCount > 0 && | |
584 desc->audioOutputPortCount > 0 && | |
585 !desc->isSynth) { | |
586 effect = true; | |
587 } | |
588 | |
589 if (desc->audioInputPortCount == 0) { | |
590 generator = true; | |
591 } | |
592 | |
593 if (output != "A") { | |
594 int outputNo = output.toInt(); | |
595 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) { | |
596 outputLabel = desc->controlOutputPortNames[outputNo].c_str(); | |
597 } | |
598 } | |
599 | |
600 size_t sampleRate = inputModel->getSampleRate(); | |
601 size_t blockSize = 1024; | |
602 size_t channels = 1; | |
603 if (effect && source) { | |
604 sampleRate = source->getTargetSampleRate(); | |
605 blockSize = source->getTargetBlockSize(); | |
606 channels = source->getTargetChannelCount(); | |
607 } | |
608 | |
609 RealTimePluginInstance *rtp = factory->instantiatePlugin | |
610 (id, 0, 0, sampleRate, blockSize, channels); | |
611 | |
612 plugin = rtp; | |
613 | |
614 if (effect && source && rtp) { | |
615 source->setAuditioningPlugin(rtp); | |
616 } | |
617 } | |
618 | |
619 if (plugin) { | |
620 | |
621 context = PluginTransform::ExecutionContext(context.channel, plugin); | |
622 | |
623 if (configurationXml != "") { | |
624 PluginXml(plugin).setParametersFromXml(configurationXml); | |
625 } | |
626 | |
627 int sourceChannels = 1; | |
628 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) { | |
629 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel) | |
630 ->getChannelCount(); | |
631 } | |
632 | |
633 int minChannels = 1, maxChannels = sourceChannels; | |
634 getChannelRange(identifier, plugin, minChannels, maxChannels); | |
635 | |
636 int targetChannels = sourceChannels; | |
637 if (!effect) { | |
638 if (sourceChannels < minChannels) targetChannels = minChannels; | |
639 if (sourceChannels > maxChannels) targetChannels = maxChannels; | |
640 } | |
641 | |
642 int defaultChannel = context.channel; | |
643 | |
644 PluginParameterDialog *dialog = new PluginParameterDialog(plugin); | |
645 | |
646 if (candidateModelNames.size() > 1 && !generator) { | |
647 dialog->setCandidateInputModels(candidateModelNames); | |
648 } | |
649 | |
650 if (targetChannels > 0) { | |
651 dialog->setChannelArrangement(sourceChannels, targetChannels, | |
652 defaultChannel); | |
653 } | |
654 | |
655 dialog->setOutputLabel(outputLabel, outputDescription); | |
656 | |
657 dialog->setShowProcessingOptions(true, frequency); | |
658 | |
659 if (dialog->exec() == QDialog::Accepted) { | |
660 ok = true; | |
661 } | |
662 | |
663 QString selectedInput = dialog->getInputModel(); | |
664 if (selectedInput != "") { | |
665 if (modelMap.find(selectedInput) != modelMap.end()) { | |
666 inputModel = modelMap[selectedInput]; | |
667 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl; | |
668 } else { | |
669 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl; | |
670 } | |
671 } | |
672 | |
673 configurationXml = PluginXml(plugin).toXmlString(); | |
674 context.channel = dialog->getChannel(); | |
675 | |
676 dialog->getProcessingParameters(context.stepSize, | |
677 context.blockSize, | |
678 context.windowType); | |
679 | |
680 context.makeConsistentWithPlugin(plugin); | |
681 | |
682 delete dialog; | |
683 | |
684 if (effect && source) { | |
685 source->setAuditioningPlugin(0); // will delete our plugin | |
686 } else { | |
687 delete plugin; | |
688 } | |
689 } | |
690 | |
691 if (ok) m_lastConfigurations[identifier] = configurationXml; | |
692 | |
693 return ok ? inputModel : 0; | |
694 } | |
695 | |
696 PluginTransform::ExecutionContext | |
697 TransformFactory::getDefaultContextForTransform(TransformId identifier, | |
698 Model *inputModel) | |
699 { | |
700 PluginTransform::ExecutionContext context(-1); | |
701 | |
702 QString id = identifier.section(':', 0, 2); | |
703 | |
704 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
705 | |
706 Vamp::Plugin *vp = | |
707 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin | |
708 (id, inputModel ? inputModel->getSampleRate() : 48000); | |
709 | |
710 if (vp) context = PluginTransform::ExecutionContext(-1, vp); | |
711 | |
712 } | |
713 | |
714 return context; | |
715 } | |
716 | |
717 Transform * | |
718 TransformFactory::createTransform(TransformId identifier, Model *inputModel, | |
719 const PluginTransform::ExecutionContext &context, | |
720 QString configurationXml) | |
721 { | |
722 Transform *transform = 0; | |
723 | |
724 QString id = identifier.section(':', 0, 2); | |
725 QString output = identifier.section(':', 3); | |
726 | |
727 if (FeatureExtractionPluginFactory::instanceFor(id)) { | |
728 transform = new FeatureExtractionPluginTransform(inputModel, | |
729 id, | |
730 context, | |
731 configurationXml, | |
732 output); | |
733 } else if (RealTimePluginFactory::instanceFor(id)) { | |
734 transform = new RealTimePluginTransform(inputModel, | |
735 id, | |
736 context, | |
737 configurationXml, | |
738 getTransformUnits(identifier), | |
739 output == "A" ? -1 : | |
740 output.toInt()); | |
741 } else { | |
742 std::cerr << "TransformFactory::createTransform: Unknown transform \"" | |
743 << identifier.toStdString() << "\"" << std::endl; | |
744 return transform; | |
745 } | |
746 | |
747 if (transform) transform->setObjectName(identifier); | |
748 return transform; | |
749 } | |
750 | |
751 Model * | |
752 TransformFactory::transform(TransformId identifier, Model *inputModel, | |
753 const PluginTransform::ExecutionContext &context, | |
754 QString configurationXml) | |
755 { | |
756 Transform *t = createTransform(identifier, inputModel, context, | |
757 configurationXml); | |
758 | |
759 if (!t) return 0; | |
760 | |
761 connect(t, SIGNAL(finished()), this, SLOT(transformFinished())); | |
762 | |
763 m_runningTransforms.insert(t); | |
764 | |
765 t->start(); | |
766 Model *model = t->detachOutputModel(); | |
767 | |
768 if (model) { | |
769 QString imn = inputModel->objectName(); | |
770 QString trn = getTransformFriendlyName(identifier); | |
771 if (imn != "") { | |
772 if (trn != "") { | |
773 model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); | |
774 } else { | |
775 model->setObjectName(imn); | |
776 } | |
777 } else if (trn != "") { | |
778 model->setObjectName(trn); | |
779 } | |
780 } | |
781 | |
782 return model; | |
783 } | |
784 | |
785 void | |
786 TransformFactory::transformFinished() | |
787 { | |
788 QObject *s = sender(); | |
789 Transform *transform = dynamic_cast<Transform *>(s); | |
790 | |
791 std::cerr << "TransformFactory::transformFinished(" << transform << ")" << std::endl; | |
792 | |
793 if (!transform) { | |
794 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl; | |
795 return; | |
796 } | |
797 | |
798 if (m_runningTransforms.find(transform) == m_runningTransforms.end()) { | |
799 std::cerr << "WARNING: TransformFactory::transformFinished(" | |
800 << transform | |
801 << "): I have no record of this transform running!" | |
802 << std::endl; | |
803 } | |
804 | |
805 m_runningTransforms.erase(transform); | |
806 | |
807 transform->wait(); // unnecessary but reassuring | |
808 delete transform; | |
809 } | |
810 | |
811 void | |
812 TransformFactory::modelAboutToBeDeleted(Model *m) | |
813 { | |
814 TransformSet affected; | |
815 | |
816 for (TransformSet::iterator i = m_runningTransforms.begin(); | |
817 i != m_runningTransforms.end(); ++i) { | |
818 | |
819 Transform *t = *i; | |
820 | |
821 if (t->getInputModel() == m || t->getOutputModel() == m) { | |
822 affected.insert(t); | |
823 } | |
824 } | |
825 | |
826 for (TransformSet::iterator i = affected.begin(); | |
827 i != affected.end(); ++i) { | |
828 | |
829 Transform *t = *i; | |
830 | |
831 t->abandon(); | |
832 | |
833 t->wait(); // this should eventually call back on | |
834 // transformFinished, which will remove from | |
835 // m_runningTransforms and delete. | |
836 } | |
837 } | |
838 |