Chris@320
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@320
|
2
|
Chris@320
|
3 /*
|
Chris@320
|
4 Sonic Visualiser
|
Chris@320
|
5 An audio file viewer and annotation editor.
|
Chris@320
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@328
|
7 This file copyright 2006-2007 Chris Cannam and QMUL.
|
Chris@320
|
8
|
Chris@320
|
9 This program is free software; you can redistribute it and/or
|
Chris@320
|
10 modify it under the terms of the GNU General Public License as
|
Chris@320
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@320
|
12 License, or (at your option) any later version. See the file
|
Chris@320
|
13 COPYING included with this distribution for more information.
|
Chris@320
|
14 */
|
Chris@320
|
15
|
Chris@320
|
16 #include "Transform.h"
|
Chris@320
|
17
|
Chris@328
|
18 #include "plugin/PluginIdentifier.h"
|
Chris@328
|
19
|
Chris@332
|
20 #include "plugin/FeatureExtractionPluginFactory.h"
|
Chris@332
|
21
|
Chris@350
|
22 #include <QXmlAttributes>
|
Chris@350
|
23
|
Chris@350
|
24 #include <QDomDocument>
|
Chris@350
|
25 #include <QDomElement>
|
Chris@350
|
26 #include <QDomNamedNodeMap>
|
Chris@350
|
27 #include <QDomAttr>
|
Chris@350
|
28
|
Chris@350
|
29 #include <QTextStream>
|
Chris@350
|
30
|
Chris@350
|
31 #include <iostream>
|
Chris@350
|
32
|
Chris@328
|
33 Transform::Transform() :
|
Chris@328
|
34 m_stepSize(0),
|
Chris@328
|
35 m_blockSize(0),
|
Chris@328
|
36 m_windowType(HanningWindow),
|
Chris@328
|
37 m_sampleRate(0)
|
Chris@320
|
38 {
|
Chris@320
|
39 }
|
Chris@320
|
40
|
Chris@350
|
41 Transform::Transform(QString xml) :
|
Chris@350
|
42 m_stepSize(0),
|
Chris@350
|
43 m_blockSize(0),
|
Chris@350
|
44 m_windowType(HanningWindow),
|
Chris@350
|
45 m_sampleRate(0)
|
Chris@350
|
46 {
|
Chris@350
|
47 QDomDocument doc;
|
Chris@350
|
48
|
Chris@350
|
49 QString error;
|
Chris@350
|
50 int errorLine;
|
Chris@350
|
51 int errorColumn;
|
Chris@350
|
52
|
Chris@350
|
53 if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
|
Chris@350
|
54 std::cerr << "Transform::Transform: Error in parsing XML: "
|
Chris@350
|
55 << error.toStdString() << " at line " << errorLine
|
Chris@350
|
56 << ", column " << errorColumn << std::endl;
|
Chris@350
|
57 std::cerr << "Input follows:" << std::endl;
|
Chris@350
|
58 std::cerr << xml.toStdString() << std::endl;
|
Chris@350
|
59 std::cerr << "Input ends." << std::endl;
|
Chris@350
|
60 return;
|
Chris@350
|
61 }
|
Chris@350
|
62
|
Chris@350
|
63 QDomElement transformElt = doc.firstChildElement("transform");
|
Chris@350
|
64 QDomNamedNodeMap attrNodes = transformElt.attributes();
|
Chris@350
|
65 QXmlAttributes attrs;
|
Chris@350
|
66
|
Chris@350
|
67 for (unsigned int i = 0; i < attrNodes.length(); ++i) {
|
Chris@350
|
68 QDomAttr attr = attrNodes.item(i).toAttr();
|
Chris@350
|
69 if (!attr.isNull()) attrs.append(attr.name(), "", "", attr.value());
|
Chris@350
|
70 }
|
Chris@350
|
71
|
Chris@350
|
72 setFromXmlAttributes(attrs);
|
Chris@350
|
73
|
Chris@350
|
74 for (QDomElement paramElt = transformElt.firstChildElement("parameter");
|
Chris@350
|
75 !paramElt.isNull();
|
Chris@350
|
76 paramElt = paramElt.nextSiblingElement("parameter")) {
|
Chris@350
|
77
|
Chris@350
|
78 QDomNamedNodeMap paramAttrs = paramElt.attributes();
|
Chris@350
|
79
|
Chris@350
|
80 QDomAttr nameAttr = paramAttrs.namedItem("name").toAttr();
|
Chris@350
|
81 if (nameAttr.isNull() || nameAttr.value() == "") continue;
|
Chris@350
|
82
|
Chris@350
|
83 QDomAttr valueAttr = paramAttrs.namedItem("value").toAttr();
|
Chris@350
|
84 if (valueAttr.isNull() || valueAttr.value() == "") continue;
|
Chris@350
|
85
|
Chris@350
|
86 setParameter(nameAttr.value(), valueAttr.value().toFloat());
|
Chris@350
|
87 }
|
Chris@350
|
88
|
Chris@350
|
89 for (QDomElement configElt = transformElt.firstChildElement("configuration");
|
Chris@350
|
90 !configElt.isNull();
|
Chris@350
|
91 configElt = configElt.nextSiblingElement("configuration")) {
|
Chris@350
|
92
|
Chris@350
|
93 QDomNamedNodeMap configAttrs = configElt.attributes();
|
Chris@350
|
94
|
Chris@350
|
95 QDomAttr nameAttr = configAttrs.namedItem("name").toAttr();
|
Chris@350
|
96 if (nameAttr.isNull() || nameAttr.value() == "") continue;
|
Chris@350
|
97
|
Chris@350
|
98 QDomAttr valueAttr = configAttrs.namedItem("value").toAttr();
|
Chris@350
|
99 if (valueAttr.isNull() || valueAttr.value() == "") continue;
|
Chris@350
|
100
|
Chris@350
|
101 setConfigurationValue(nameAttr.value(), valueAttr.value());
|
Chris@350
|
102 }
|
Chris@350
|
103 }
|
Chris@350
|
104
|
Chris@320
|
105 Transform::~Transform()
|
Chris@320
|
106 {
|
Chris@320
|
107 }
|
Chris@320
|
108
|
Chris@350
|
109 bool
|
Chris@400
|
110 Transform::operator==(const Transform &t) const
|
Chris@350
|
111 {
|
Chris@350
|
112 return
|
Chris@350
|
113 m_id == t.m_id &&
|
Chris@350
|
114 m_parameters == t.m_parameters &&
|
Chris@350
|
115 m_configuration == t.m_configuration &&
|
Chris@350
|
116 m_program == t.m_program &&
|
Chris@350
|
117 m_stepSize == t.m_stepSize &&
|
Chris@350
|
118 m_blockSize == t.m_blockSize &&
|
Chris@350
|
119 m_windowType == t.m_windowType &&
|
Chris@350
|
120 m_startTime == t.m_startTime &&
|
Chris@350
|
121 m_duration == t.m_duration &&
|
Chris@350
|
122 m_sampleRate == t.m_sampleRate;
|
Chris@350
|
123 }
|
Chris@350
|
124
|
Chris@400
|
125 bool
|
Chris@400
|
126 Transform::operator<(const Transform &t) const
|
Chris@400
|
127 {
|
Chris@400
|
128 if (m_id != t.m_id) {
|
Chris@400
|
129 return m_id < t.m_id;
|
Chris@400
|
130 }
|
Chris@400
|
131 if (m_parameters != t.m_parameters) {
|
Chris@400
|
132 return mapLessThan<QString, float>(m_parameters, t.m_parameters);
|
Chris@400
|
133 }
|
Chris@400
|
134 if (m_configuration != t.m_configuration) {
|
Chris@400
|
135 return mapLessThan<QString, QString>(m_configuration, t.m_configuration);
|
Chris@400
|
136 }
|
Chris@400
|
137 if (m_program != t.m_program) {
|
Chris@400
|
138 return m_program < t.m_program;
|
Chris@400
|
139 }
|
Chris@400
|
140 if (m_stepSize != t.m_stepSize) {
|
Chris@400
|
141 return m_stepSize < t.m_stepSize;
|
Chris@400
|
142 }
|
Chris@400
|
143 if (m_blockSize != t.m_blockSize) {
|
Chris@400
|
144 return m_blockSize < t.m_blockSize;
|
Chris@400
|
145 }
|
Chris@400
|
146 if (m_windowType != t.m_windowType) {
|
Chris@400
|
147 return m_windowType < t.m_windowType;
|
Chris@400
|
148 }
|
Chris@400
|
149 if (m_startTime != t.m_startTime) {
|
Chris@400
|
150 return m_startTime < t.m_startTime;
|
Chris@400
|
151 }
|
Chris@400
|
152 if (m_duration != t.m_duration) {
|
Chris@400
|
153 return m_duration < t.m_duration;
|
Chris@400
|
154 }
|
Chris@400
|
155 if (m_sampleRate != t.m_sampleRate) {
|
Chris@400
|
156 return m_sampleRate < t.m_sampleRate;
|
Chris@400
|
157 }
|
Chris@400
|
158 return false;
|
Chris@400
|
159 }
|
Chris@400
|
160
|
Chris@350
|
161 void
|
Chris@350
|
162 Transform::setIdentifier(TransformId id)
|
Chris@350
|
163 {
|
Chris@350
|
164 m_id = id;
|
Chris@350
|
165 }
|
Chris@350
|
166
|
Chris@350
|
167 TransformId
|
Chris@350
|
168 Transform::getIdentifier() const
|
Chris@350
|
169 {
|
Chris@350
|
170 return m_id;
|
Chris@350
|
171 }
|
Chris@350
|
172
|
Chris@328
|
173 QString
|
Chris@328
|
174 Transform::createIdentifier(QString type, QString soName, QString label,
|
Chris@328
|
175 QString output)
|
Chris@328
|
176 {
|
Chris@328
|
177 QString pluginId = PluginIdentifier::createIdentifier(type, soName, label);
|
Chris@328
|
178 return pluginId + ":" + output;
|
Chris@328
|
179 }
|
Chris@328
|
180
|
Chris@328
|
181 void
|
Chris@328
|
182 Transform::parseIdentifier(QString identifier,
|
Chris@328
|
183 QString &type, QString &soName,
|
Chris@328
|
184 QString &label, QString &output)
|
Chris@328
|
185 {
|
Chris@328
|
186 output = identifier.section(':', 3);
|
Chris@328
|
187 PluginIdentifier::parseIdentifier(identifier.section(':', 0, 2),
|
Chris@328
|
188 type, soName, label);
|
Chris@328
|
189 }
|
Chris@328
|
190
|
Chris@328
|
191 Transform::Type
|
Chris@328
|
192 Transform::getType() const
|
Chris@328
|
193 {
|
Chris@332
|
194 if (FeatureExtractionPluginFactory::instanceFor(getPluginIdentifier())) {
|
Chris@332
|
195 return FeatureExtraction;
|
Chris@332
|
196 } else {
|
Chris@332
|
197 // We don't have an unknown/invalid return value, so always
|
Chris@332
|
198 // return this
|
Chris@332
|
199 return RealTimeEffect;
|
Chris@332
|
200 }
|
Chris@328
|
201 }
|
Chris@328
|
202
|
Chris@328
|
203 QString
|
Chris@328
|
204 Transform::getPluginIdentifier() const
|
Chris@328
|
205 {
|
Chris@328
|
206 return m_id.section(':', 0, 2);
|
Chris@328
|
207 }
|
Chris@328
|
208
|
Chris@328
|
209 QString
|
Chris@328
|
210 Transform::getOutput() const
|
Chris@328
|
211 {
|
Chris@328
|
212 return m_id.section(':', 3);
|
Chris@328
|
213 }
|
Chris@328
|
214
|
Chris@353
|
215 void
|
Chris@353
|
216 Transform::setPluginIdentifier(QString pluginIdentifier)
|
Chris@353
|
217 {
|
Chris@353
|
218 m_id = pluginIdentifier + ':' + getOutput();
|
Chris@353
|
219 }
|
Chris@353
|
220
|
Chris@353
|
221 void
|
Chris@353
|
222 Transform::setOutput(QString output)
|
Chris@353
|
223 {
|
Chris@353
|
224 m_id = getPluginIdentifier() + ':' + output;
|
Chris@353
|
225 }
|
Chris@353
|
226
|
Chris@353
|
227 TransformId
|
Chris@353
|
228 Transform::getIdentifierForPluginOutput(QString pluginIdentifier,
|
Chris@353
|
229 QString output)
|
Chris@353
|
230 {
|
Chris@353
|
231 return pluginIdentifier + ':' + output;
|
Chris@353
|
232 }
|
Chris@353
|
233
|
Chris@350
|
234 const Transform::ParameterMap &
|
Chris@350
|
235 Transform::getParameters() const
|
Chris@350
|
236 {
|
Chris@350
|
237 return m_parameters;
|
Chris@350
|
238 }
|
Chris@350
|
239
|
Chris@328
|
240 void
|
Chris@350
|
241 Transform::setParameters(const ParameterMap &pm)
|
Chris@328
|
242 {
|
Chris@350
|
243 m_parameters = pm;
|
Chris@350
|
244 }
|
Chris@350
|
245
|
Chris@350
|
246 void
|
Chris@350
|
247 Transform::setParameter(QString name, float value)
|
Chris@350
|
248 {
|
Chris@350
|
249 std::cerr << "Transform::setParameter(" << name.toStdString()
|
Chris@350
|
250 << ") -> " << value << std::endl;
|
Chris@350
|
251 m_parameters[name] = value;
|
Chris@350
|
252 }
|
Chris@350
|
253
|
Chris@350
|
254 const Transform::ConfigurationMap &
|
Chris@350
|
255 Transform::getConfiguration() const
|
Chris@350
|
256 {
|
Chris@350
|
257 return m_configuration;
|
Chris@350
|
258 }
|
Chris@350
|
259
|
Chris@350
|
260 void
|
Chris@350
|
261 Transform::setConfiguration(const ConfigurationMap &cm)
|
Chris@350
|
262 {
|
Chris@350
|
263 m_configuration = cm;
|
Chris@350
|
264 }
|
Chris@350
|
265
|
Chris@350
|
266 void
|
Chris@350
|
267 Transform::setConfigurationValue(QString name, QString value)
|
Chris@350
|
268 {
|
Chris@350
|
269 std::cerr << "Transform::setConfigurationValue(" << name.toStdString()
|
Chris@350
|
270 << ") -> " << value.toStdString() << std::endl;
|
Chris@350
|
271 m_configuration[name] = value;
|
Chris@350
|
272 }
|
Chris@350
|
273
|
Chris@350
|
274 QString
|
Chris@366
|
275 Transform::getPluginVersion() const
|
Chris@366
|
276 {
|
Chris@366
|
277 return m_pluginVersion;
|
Chris@366
|
278 }
|
Chris@366
|
279
|
Chris@366
|
280 void
|
Chris@366
|
281 Transform::setPluginVersion(QString version)
|
Chris@366
|
282 {
|
Chris@366
|
283 m_pluginVersion = version;
|
Chris@366
|
284 }
|
Chris@366
|
285
|
Chris@366
|
286 QString
|
Chris@350
|
287 Transform::getProgram() const
|
Chris@350
|
288 {
|
Chris@350
|
289 return m_program;
|
Chris@350
|
290 }
|
Chris@350
|
291
|
Chris@350
|
292 void
|
Chris@350
|
293 Transform::setProgram(QString program)
|
Chris@350
|
294 {
|
Chris@350
|
295 m_program = program;
|
Chris@350
|
296 }
|
Chris@350
|
297
|
Chris@328
|
298
|
Chris@350
|
299 size_t
|
Chris@350
|
300 Transform::getStepSize() const
|
Chris@350
|
301 {
|
Chris@350
|
302 return m_stepSize;
|
Chris@328
|
303 }
|
Chris@350
|
304
|
Chris@350
|
305 void
|
Chris@350
|
306 Transform::setStepSize(size_t s)
|
Chris@350
|
307 {
|
Chris@350
|
308 m_stepSize = s;
|
Chris@350
|
309 }
|
Chris@350
|
310
|
Chris@350
|
311 size_t
|
Chris@350
|
312 Transform::getBlockSize() const
|
Chris@350
|
313 {
|
Chris@350
|
314 return m_blockSize;
|
Chris@350
|
315 }
|
Chris@350
|
316
|
Chris@350
|
317 void
|
Chris@350
|
318 Transform::setBlockSize(size_t s)
|
Chris@350
|
319 {
|
Chris@350
|
320 m_blockSize = s;
|
Chris@350
|
321 }
|
Chris@350
|
322
|
Chris@350
|
323 WindowType
|
Chris@350
|
324 Transform::getWindowType() const
|
Chris@350
|
325 {
|
Chris@350
|
326 return m_windowType;
|
Chris@350
|
327 }
|
Chris@350
|
328
|
Chris@350
|
329 void
|
Chris@350
|
330 Transform::setWindowType(WindowType type)
|
Chris@350
|
331 {
|
Chris@350
|
332 m_windowType = type;
|
Chris@350
|
333 }
|
Chris@350
|
334
|
Chris@350
|
335 RealTime
|
Chris@350
|
336 Transform::getStartTime() const
|
Chris@350
|
337 {
|
Chris@350
|
338 return m_startTime;
|
Chris@350
|
339 }
|
Chris@350
|
340
|
Chris@350
|
341 void
|
Chris@350
|
342 Transform::setStartTime(RealTime t)
|
Chris@350
|
343 {
|
Chris@350
|
344 m_startTime = t;
|
Chris@350
|
345 }
|
Chris@350
|
346
|
Chris@350
|
347 RealTime
|
Chris@350
|
348 Transform::getDuration() const
|
Chris@350
|
349 {
|
Chris@350
|
350 return m_duration;
|
Chris@350
|
351 }
|
Chris@350
|
352
|
Chris@350
|
353 void
|
Chris@350
|
354 Transform::setDuration(RealTime d)
|
Chris@350
|
355 {
|
Chris@350
|
356 m_duration = d;
|
Chris@350
|
357 }
|
Chris@350
|
358
|
Chris@350
|
359 float
|
Chris@350
|
360 Transform::getSampleRate() const
|
Chris@350
|
361 {
|
Chris@350
|
362 return m_sampleRate;
|
Chris@350
|
363 }
|
Chris@350
|
364
|
Chris@350
|
365 void
|
Chris@350
|
366 Transform::setSampleRate(float rate)
|
Chris@350
|
367 {
|
Chris@350
|
368 m_sampleRate = rate;
|
Chris@350
|
369 }
|
Chris@350
|
370
|
Chris@350
|
371 void
|
Chris@350
|
372 Transform::toXml(QTextStream &out, QString indent, QString extraAttributes) const
|
Chris@350
|
373 {
|
Chris@350
|
374 out << indent;
|
Chris@350
|
375
|
Chris@350
|
376 bool haveContent = true;
|
Chris@350
|
377 if (m_parameters.empty() && m_configuration.empty()) haveContent = false;
|
Chris@350
|
378
|
Chris@396
|
379 out << QString("<transform\n id=\"%1\"\n pluginVersion=\"%2\"\n program=\"%3\"\n stepSize=\"%4\"\n blockSize=\"%5\"\n windowType=\"%6\"\n startTime=\"%7\"\n duration=\"%8\"\n sampleRate=\"%9\"")
|
Chris@350
|
380 .arg(encodeEntities(m_id))
|
Chris@366
|
381 .arg(encodeEntities(m_pluginVersion))
|
Chris@350
|
382 .arg(encodeEntities(m_program))
|
Chris@350
|
383 .arg(m_stepSize)
|
Chris@350
|
384 .arg(m_blockSize)
|
Chris@350
|
385 .arg(encodeEntities(Window<float>::getNameForType(m_windowType).c_str()))
|
Chris@350
|
386 .arg(encodeEntities(m_startTime.toString().c_str()))
|
Chris@350
|
387 .arg(encodeEntities(m_duration.toString().c_str()))
|
Chris@366
|
388 .arg(m_sampleRate);
|
Chris@366
|
389
|
Chris@366
|
390 if (extraAttributes != "") {
|
Chris@366
|
391 out << " " << extraAttributes;
|
Chris@366
|
392 }
|
Chris@350
|
393
|
Chris@350
|
394 if (haveContent) {
|
Chris@350
|
395
|
Chris@350
|
396 out << ">\n";
|
Chris@350
|
397
|
Chris@350
|
398 for (ParameterMap::const_iterator i = m_parameters.begin();
|
Chris@350
|
399 i != m_parameters.end(); ++i) {
|
Chris@350
|
400 out << indent << " "
|
Chris@350
|
401 << QString("<parameter name=\"%1\" value=\"%2\"/>\n")
|
Chris@350
|
402 .arg(encodeEntities(i->first))
|
Chris@350
|
403 .arg(i->second);
|
Chris@350
|
404 }
|
Chris@350
|
405
|
Chris@350
|
406 for (ConfigurationMap::const_iterator i = m_configuration.begin();
|
Chris@350
|
407 i != m_configuration.end(); ++i) {
|
Chris@350
|
408 out << indent << " "
|
Chris@350
|
409 << QString("<configuration name=\"%1\" value=\"%2\"/>\n")
|
Chris@350
|
410 .arg(encodeEntities(i->first))
|
Chris@350
|
411 .arg(encodeEntities(i->second));
|
Chris@350
|
412 }
|
Chris@350
|
413
|
Chris@350
|
414 out << indent << "</transform>\n";
|
Chris@350
|
415
|
Chris@350
|
416 } else {
|
Chris@350
|
417
|
Chris@350
|
418 out << "/>\n";
|
Chris@350
|
419 }
|
Chris@350
|
420 }
|
Chris@350
|
421
|
Chris@350
|
422 void
|
Chris@350
|
423 Transform::setFromXmlAttributes(const QXmlAttributes &attrs)
|
Chris@350
|
424 {
|
Chris@350
|
425 if (attrs.value("id") != "") {
|
Chris@350
|
426 setIdentifier(attrs.value("id"));
|
Chris@350
|
427 }
|
Chris@350
|
428
|
Chris@366
|
429 if (attrs.value("pluginVersion") != "") {
|
Chris@366
|
430 setPluginVersion(attrs.value("pluginVersion"));
|
Chris@366
|
431 }
|
Chris@366
|
432
|
Chris@350
|
433 if (attrs.value("program") != "") {
|
Chris@350
|
434 setProgram(attrs.value("program"));
|
Chris@350
|
435 }
|
Chris@350
|
436
|
Chris@350
|
437 if (attrs.value("stepSize") != "") {
|
Chris@350
|
438 setStepSize(attrs.value("stepSize").toInt());
|
Chris@350
|
439 }
|
Chris@350
|
440
|
Chris@350
|
441 if (attrs.value("blockSize") != "") {
|
Chris@350
|
442 setBlockSize(attrs.value("blockSize").toInt());
|
Chris@350
|
443 }
|
Chris@350
|
444
|
Chris@350
|
445 if (attrs.value("windowType") != "") {
|
Chris@350
|
446 setWindowType(Window<float>::getTypeForName
|
Chris@350
|
447 (attrs.value("windowType").toStdString()));
|
Chris@350
|
448 }
|
Chris@350
|
449
|
Chris@350
|
450 if (attrs.value("startTime") != "") {
|
Chris@350
|
451 setStartTime(RealTime::fromString(attrs.value("startTime").toStdString()));
|
Chris@350
|
452 }
|
Chris@350
|
453
|
Chris@350
|
454 if (attrs.value("duration") != "") {
|
Chris@350
|
455 setStartTime(RealTime::fromString(attrs.value("duration").toStdString()));
|
Chris@350
|
456 }
|
Chris@350
|
457
|
Chris@350
|
458 if (attrs.value("sampleRate") != "") {
|
Chris@350
|
459 setSampleRate(attrs.value("sampleRate").toFloat());
|
Chris@350
|
460 }
|
Chris@350
|
461 }
|
Chris@350
|
462
|