Chris@49
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@52
|
4 Sonic Visualiser
|
Chris@52
|
5 An audio file viewer and annotation editor.
|
Chris@52
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@52
|
7 This file copyright 2006 Chris Cannam.
|
Chris@0
|
8
|
Chris@52
|
9 This program is free software; you can redistribute it and/or
|
Chris@52
|
10 modify it under the terms of the GNU General Public License as
|
Chris@52
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@52
|
12 License, or (at your option) any later version. See the file
|
Chris@52
|
13 COPYING included with this distribution for more information.
|
Chris@0
|
14 */
|
Chris@0
|
15
|
Chris@0
|
16 #include "TransformFactory.h"
|
Chris@0
|
17
|
Chris@0
|
18 #include "FeatureExtractionPluginTransform.h"
|
Chris@0
|
19
|
Chris@0
|
20 #include "plugin/FeatureExtractionPluginFactory.h"
|
Chris@0
|
21
|
Chris@56
|
22 #include "widgets/PluginParameterDialog.h"
|
Chris@56
|
23
|
Chris@0
|
24 #include <iostream>
|
Chris@0
|
25
|
Chris@0
|
26 TransformFactory *
|
Chris@0
|
27 TransformFactory::m_instance = new TransformFactory;
|
Chris@0
|
28
|
Chris@0
|
29 TransformFactory *
|
Chris@0
|
30 TransformFactory::instance()
|
Chris@0
|
31 {
|
Chris@0
|
32 return m_instance;
|
Chris@0
|
33 }
|
Chris@0
|
34
|
Chris@0
|
35 TransformFactory::~TransformFactory()
|
Chris@0
|
36 {
|
Chris@0
|
37 }
|
Chris@0
|
38
|
Chris@0
|
39 TransformFactory::TransformList
|
Chris@0
|
40 TransformFactory::getAllTransforms()
|
Chris@0
|
41 {
|
Chris@16
|
42 if (m_transforms.empty()) populateTransforms();
|
Chris@16
|
43
|
Chris@0
|
44 TransformList list;
|
Chris@56
|
45 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
|
Chris@16
|
46 i != m_transforms.end(); ++i) {
|
Chris@56
|
47 list.push_back(i->second);
|
Chris@16
|
48 }
|
Chris@0
|
49
|
Chris@16
|
50 return list;
|
Chris@16
|
51 }
|
Chris@16
|
52
|
Chris@16
|
53 void
|
Chris@16
|
54 TransformFactory::populateTransforms()
|
Chris@16
|
55 {
|
Chris@0
|
56 std::vector<QString> fexplugs =
|
Chris@0
|
57 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
|
Chris@0
|
58
|
Chris@47
|
59 std::map<QString, QString> makers;
|
Chris@47
|
60
|
Chris@0
|
61 for (size_t i = 0; i < fexplugs.size(); ++i) {
|
Chris@0
|
62
|
Chris@0
|
63 QString pluginId = fexplugs[i];
|
Chris@0
|
64
|
Chris@0
|
65 FeatureExtractionPluginFactory *factory =
|
Chris@0
|
66 FeatureExtractionPluginFactory::instanceFor(pluginId);
|
Chris@0
|
67
|
Chris@20
|
68 if (!factory) {
|
Chris@20
|
69 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
|
Chris@20
|
70 continue;
|
Chris@20
|
71 }
|
Chris@0
|
72
|
Chris@20
|
73 FeatureExtractionPlugin *plugin =
|
Chris@20
|
74 factory->instantiatePlugin(pluginId, 48000);
|
Chris@0
|
75
|
Chris@20
|
76 if (!plugin) {
|
Chris@20
|
77 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
|
Chris@20
|
78 continue;
|
Chris@20
|
79 }
|
Chris@20
|
80
|
Chris@20
|
81 QString pluginDescription = plugin->getDescription().c_str();
|
Chris@20
|
82 FeatureExtractionPlugin::OutputList outputs =
|
Chris@20
|
83 plugin->getOutputDescriptors();
|
Chris@0
|
84
|
Chris@20
|
85 for (size_t j = 0; j < outputs.size(); ++j) {
|
Chris@0
|
86
|
Chris@20
|
87 QString transformName = QString("%1:%2")
|
Chris@20
|
88 .arg(pluginId).arg(outputs[j].name.c_str());
|
Chris@20
|
89
|
Chris@20
|
90 QString userDescription;
|
Chris@20
|
91
|
Chris@20
|
92 if (outputs.size() == 1) {
|
Chris@20
|
93 userDescription = pluginDescription;
|
Chris@20
|
94 } else {
|
Chris@20
|
95 userDescription = QString("%1: %2")
|
Chris@20
|
96 .arg(pluginDescription)
|
Chris@20
|
97 .arg(outputs[j].description.c_str());
|
Chris@0
|
98 }
|
Chris@20
|
99
|
Chris@56
|
100 bool configurable = (!plugin->getPrograms().empty() ||
|
Chris@56
|
101 !plugin->getParameterDescriptors().empty());
|
Chris@56
|
102
|
Chris@56
|
103 m_transforms[transformName] =
|
Chris@56
|
104 TransformDesc(transformName,
|
Chris@56
|
105 userDescription,
|
Chris@56
|
106 configurable);
|
Chris@47
|
107
|
Chris@47
|
108 makers[transformName] = plugin->getMaker().c_str();
|
Chris@0
|
109 }
|
Chris@0
|
110 }
|
Chris@47
|
111
|
Chris@47
|
112 // disambiguate plugins with similar descriptions
|
Chris@47
|
113
|
Chris@47
|
114 std::map<QString, int> descriptions;
|
Chris@47
|
115
|
Chris@56
|
116 for (TransformDescriptionMap::iterator i = m_transforms.begin();
|
Chris@56
|
117 i != m_transforms.end(); ++i) {
|
Chris@47
|
118
|
Chris@56
|
119 TransformDesc desc = i->second;
|
Chris@47
|
120
|
Chris@56
|
121 ++descriptions[desc.description];
|
Chris@56
|
122 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(makers[desc.name])];
|
Chris@47
|
123 }
|
Chris@47
|
124
|
Chris@47
|
125 std::map<QString, int> counts;
|
Chris@56
|
126 TransformDescriptionMap newMap;
|
Chris@47
|
127
|
Chris@56
|
128 for (TransformDescriptionMap::iterator i = m_transforms.begin();
|
Chris@56
|
129 i != m_transforms.end(); ++i) {
|
Chris@47
|
130
|
Chris@56
|
131 TransformDesc desc = i->second;
|
Chris@56
|
132 QString name = desc.name, description = desc.description;
|
Chris@47
|
133
|
Chris@47
|
134 if (descriptions[description] > 1) {
|
Chris@47
|
135 description = QString("%1 [%2]").arg(description).arg(makers[name]);
|
Chris@47
|
136 if (descriptions[description] > 1) {
|
Chris@47
|
137 description = QString("%1 <%2>")
|
Chris@47
|
138 .arg(description).arg(++counts[description]);
|
Chris@47
|
139 }
|
Chris@47
|
140 }
|
Chris@47
|
141
|
Chris@56
|
142 desc.description = description;
|
Chris@56
|
143 newMap[name] = desc;
|
Chris@47
|
144 }
|
Chris@47
|
145
|
Chris@47
|
146 m_transforms = newMap;
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 QString
|
Chris@16
|
150 TransformFactory::getTransformDescription(TransformName name)
|
Chris@16
|
151 {
|
Chris@16
|
152 if (m_transforms.find(name) != m_transforms.end()) {
|
Chris@56
|
153 return m_transforms[name].description;
|
Chris@16
|
154 } else return "";
|
Chris@0
|
155 }
|
Chris@0
|
156
|
Chris@18
|
157 QString
|
Chris@18
|
158 TransformFactory::getTransformFriendlyName(TransformName name)
|
Chris@18
|
159 {
|
Chris@18
|
160 QString description = getTransformDescription(name);
|
Chris@18
|
161
|
Chris@18
|
162 int i = description.indexOf(':');
|
Chris@18
|
163 if (i >= 0) {
|
Chris@18
|
164 return description.remove(0, i + 2);
|
Chris@18
|
165 } else {
|
Chris@18
|
166 return description;
|
Chris@18
|
167 }
|
Chris@18
|
168 }
|
Chris@18
|
169
|
Chris@56
|
170 bool
|
Chris@57
|
171 TransformFactory::isTransformConfigurable(TransformName name)
|
Chris@57
|
172 {
|
Chris@57
|
173 if (m_transforms.find(name) != m_transforms.end()) {
|
Chris@57
|
174 return m_transforms[name].configurable;
|
Chris@57
|
175 } else return false;
|
Chris@57
|
176 }
|
Chris@57
|
177
|
Chris@57
|
178 bool
|
Chris@56
|
179 TransformFactory::getConfigurationForTransform(TransformName name,
|
Chris@56
|
180 Model *inputModel,
|
Chris@56
|
181 QString &configurationXml)
|
Chris@0
|
182 {
|
Chris@56
|
183 QString id = name.section(':', 0, 2);
|
Chris@56
|
184 QString output = name.section(':', 3);
|
Chris@56
|
185
|
Chris@56
|
186 bool ok = false;
|
Chris@56
|
187 configurationXml = m_lastConfigurations[name];
|
Chris@56
|
188
|
Chris@56
|
189 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
|
Chris@56
|
190
|
Chris@56
|
191 if (FeatureExtractionPluginFactory::instanceFor(id)) {
|
Chris@56
|
192 FeatureExtractionPlugin *plugin =
|
Chris@56
|
193 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
|
Chris@56
|
194 (id, inputModel->getSampleRate());
|
Chris@56
|
195 if (plugin) {
|
Chris@56
|
196 if (configurationXml != "") {
|
Chris@56
|
197 plugin->setParametersFromXml(configurationXml);
|
Chris@56
|
198 }
|
Chris@56
|
199 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
|
Chris@56
|
200 if (dialog->exec() == QDialog::Accepted) {
|
Chris@56
|
201 ok = true;
|
Chris@56
|
202 }
|
Chris@56
|
203 configurationXml = plugin->toXmlString();
|
Chris@57
|
204 delete dialog;
|
Chris@56
|
205 delete plugin;
|
Chris@56
|
206 }
|
Chris@56
|
207 }
|
Chris@56
|
208
|
Chris@56
|
209 if (ok) m_lastConfigurations[name] = configurationXml;
|
Chris@56
|
210
|
Chris@56
|
211 return ok;
|
Chris@0
|
212 }
|
Chris@0
|
213
|
Chris@0
|
214 Transform *
|
Chris@0
|
215 TransformFactory::createTransform(TransformName name, Model *inputModel,
|
Chris@56
|
216 QString configurationXml, bool start)
|
Chris@0
|
217 {
|
Chris@0
|
218 Transform *transform = 0;
|
Chris@0
|
219
|
Chris@56
|
220 // The only transform type we support at the moment is the
|
Chris@56
|
221 // FeatureExtractionPluginTransform. In future we may wish to
|
Chris@56
|
222 // support e.g. RealTimePluginTransform for audio->audio or
|
Chris@56
|
223 // audio->midi transforms using standard effects plugins.
|
Chris@56
|
224
|
Chris@56
|
225 QString id = name.section(':', 0, 2);
|
Chris@56
|
226 QString output = name.section(':', 3);
|
Chris@56
|
227
|
Chris@56
|
228 if (FeatureExtractionPluginFactory::instanceFor(id)) {
|
Chris@56
|
229 transform = new FeatureExtractionPluginTransform(inputModel,
|
Chris@56
|
230 id,
|
Chris@56
|
231 configurationXml,
|
Chris@56
|
232 output);
|
Chris@0
|
233 } else {
|
Chris@56
|
234 std::cerr << "TransformFactory::createTransform: Unknown transform "
|
Chris@56
|
235 << name.toStdString() << std::endl;
|
Chris@0
|
236 }
|
Chris@0
|
237
|
Chris@0
|
238 if (start && transform) transform->start();
|
Chris@16
|
239 transform->setObjectName(name);
|
Chris@0
|
240 return transform;
|
Chris@0
|
241 }
|
Chris@0
|
242
|
Chris@0
|
243 Model *
|
Chris@56
|
244 TransformFactory::transform(TransformName name, Model *inputModel,
|
Chris@56
|
245 QString configurationXml)
|
Chris@0
|
246 {
|
Chris@56
|
247 Transform *t = createTransform(name, inputModel, configurationXml, false);
|
Chris@0
|
248
|
Chris@0
|
249 if (!t) return 0;
|
Chris@0
|
250
|
Chris@0
|
251 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
|
Chris@0
|
252
|
Chris@0
|
253 t->start();
|
Chris@0
|
254 return t->detachOutputModel();
|
Chris@0
|
255 }
|
Chris@0
|
256
|
Chris@0
|
257 void
|
Chris@0
|
258 TransformFactory::transformFinished()
|
Chris@0
|
259 {
|
Chris@0
|
260 QObject *s = sender();
|
Chris@0
|
261 Transform *transform = dynamic_cast<Transform *>(s);
|
Chris@0
|
262
|
Chris@0
|
263 if (!transform) {
|
Chris@0
|
264 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
|
Chris@0
|
265 return;
|
Chris@0
|
266 }
|
Chris@0
|
267
|
Chris@0
|
268 transform->wait(); // unnecessary but reassuring
|
Chris@0
|
269 delete transform;
|
Chris@0
|
270 }
|
Chris@0
|
271
|