annotate transform/Transform.cpp @ 628:001db550bd48

* Add option to import time+duration (or time+endtime) from CSV files (importing to Region layers) * Fix ffwd/rwd in Region layers so as to behave like time-value layers
author Chris Cannam
date Thu, 08 Jul 2010 14:22:28 +0000
parents ecbd99d5d2c4
children b4a8d8221eaf
rev   line source
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@508 34 m_summaryType(NoSummary),
Chris@328 35 m_stepSize(0),
Chris@328 36 m_blockSize(0),
Chris@328 37 m_windowType(HanningWindow),
Chris@328 38 m_sampleRate(0)
Chris@320 39 {
Chris@320 40 }
Chris@320 41
Chris@350 42 Transform::Transform(QString xml) :
Chris@508 43 m_summaryType(NoSummary),
Chris@350 44 m_stepSize(0),
Chris@350 45 m_blockSize(0),
Chris@350 46 m_windowType(HanningWindow),
Chris@350 47 m_sampleRate(0)
Chris@350 48 {
Chris@350 49 QDomDocument doc;
Chris@350 50
Chris@350 51 QString error;
Chris@350 52 int errorLine;
Chris@350 53 int errorColumn;
Chris@350 54
Chris@350 55 if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
Chris@350 56 std::cerr << "Transform::Transform: Error in parsing XML: "
Chris@350 57 << error.toStdString() << " at line " << errorLine
Chris@350 58 << ", column " << errorColumn << std::endl;
Chris@350 59 std::cerr << "Input follows:" << std::endl;
Chris@350 60 std::cerr << xml.toStdString() << std::endl;
Chris@350 61 std::cerr << "Input ends." << std::endl;
Chris@350 62 return;
Chris@350 63 }
Chris@350 64
Chris@350 65 QDomElement transformElt = doc.firstChildElement("transform");
Chris@350 66 QDomNamedNodeMap attrNodes = transformElt.attributes();
Chris@350 67 QXmlAttributes attrs;
Chris@350 68
Chris@350 69 for (unsigned int i = 0; i < attrNodes.length(); ++i) {
Chris@350 70 QDomAttr attr = attrNodes.item(i).toAttr();
Chris@350 71 if (!attr.isNull()) attrs.append(attr.name(), "", "", attr.value());
Chris@350 72 }
Chris@350 73
Chris@350 74 setFromXmlAttributes(attrs);
Chris@350 75
Chris@350 76 for (QDomElement paramElt = transformElt.firstChildElement("parameter");
Chris@350 77 !paramElt.isNull();
Chris@350 78 paramElt = paramElt.nextSiblingElement("parameter")) {
Chris@350 79
Chris@350 80 QDomNamedNodeMap paramAttrs = paramElt.attributes();
Chris@350 81
Chris@350 82 QDomAttr nameAttr = paramAttrs.namedItem("name").toAttr();
Chris@350 83 if (nameAttr.isNull() || nameAttr.value() == "") continue;
Chris@350 84
Chris@350 85 QDomAttr valueAttr = paramAttrs.namedItem("value").toAttr();
Chris@350 86 if (valueAttr.isNull() || valueAttr.value() == "") continue;
Chris@350 87
Chris@350 88 setParameter(nameAttr.value(), valueAttr.value().toFloat());
Chris@350 89 }
Chris@350 90
Chris@350 91 for (QDomElement configElt = transformElt.firstChildElement("configuration");
Chris@350 92 !configElt.isNull();
Chris@350 93 configElt = configElt.nextSiblingElement("configuration")) {
Chris@350 94
Chris@350 95 QDomNamedNodeMap configAttrs = configElt.attributes();
Chris@350 96
Chris@350 97 QDomAttr nameAttr = configAttrs.namedItem("name").toAttr();
Chris@350 98 if (nameAttr.isNull() || nameAttr.value() == "") continue;
Chris@350 99
Chris@350 100 QDomAttr valueAttr = configAttrs.namedItem("value").toAttr();
Chris@350 101 if (valueAttr.isNull() || valueAttr.value() == "") continue;
Chris@350 102
Chris@350 103 setConfigurationValue(nameAttr.value(), valueAttr.value());
Chris@350 104 }
Chris@350 105 }
Chris@350 106
Chris@320 107 Transform::~Transform()
Chris@320 108 {
Chris@320 109 }
Chris@320 110
Chris@350 111 bool
Chris@400 112 Transform::operator==(const Transform &t) const
Chris@350 113 {
Chris@583 114 bool identical =
Chris@350 115 m_id == t.m_id &&
Chris@350 116 m_parameters == t.m_parameters &&
Chris@350 117 m_configuration == t.m_configuration &&
Chris@350 118 m_program == t.m_program &&
Chris@508 119 m_summaryType == t.m_summaryType &&
Chris@350 120 m_stepSize == t.m_stepSize &&
Chris@350 121 m_blockSize == t.m_blockSize &&
Chris@350 122 m_windowType == t.m_windowType &&
Chris@350 123 m_startTime == t.m_startTime &&
Chris@350 124 m_duration == t.m_duration &&
Chris@350 125 m_sampleRate == t.m_sampleRate;
Chris@583 126 /*
Chris@583 127 std::cerr << "Transform::operator==: identical = " << identical << std::endl;
Chris@583 128 std::cerr << "A = " << std::endl;
Chris@583 129 std::cerr << toXmlString().toStdString() << std::endl;
Chris@583 130 std::cerr << "B = " << std::endl;
Chris@583 131 std::cerr << t.toXmlString().toStdString() << std::endl;
Chris@583 132 */
Chris@583 133 return identical;
Chris@350 134 }
Chris@350 135
Chris@400 136 bool
Chris@400 137 Transform::operator<(const Transform &t) const
Chris@400 138 {
Chris@400 139 if (m_id != t.m_id) {
Chris@400 140 return m_id < t.m_id;
Chris@400 141 }
Chris@400 142 if (m_parameters != t.m_parameters) {
Chris@400 143 return mapLessThan<QString, float>(m_parameters, t.m_parameters);
Chris@400 144 }
Chris@400 145 if (m_configuration != t.m_configuration) {
Chris@400 146 return mapLessThan<QString, QString>(m_configuration, t.m_configuration);
Chris@400 147 }
Chris@400 148 if (m_program != t.m_program) {
Chris@400 149 return m_program < t.m_program;
Chris@400 150 }
Chris@508 151 if (m_summaryType != t.m_summaryType) {
Chris@508 152 return int(m_summaryType) < int(t.m_summaryType);
Chris@508 153 }
Chris@400 154 if (m_stepSize != t.m_stepSize) {
Chris@400 155 return m_stepSize < t.m_stepSize;
Chris@400 156 }
Chris@400 157 if (m_blockSize != t.m_blockSize) {
Chris@400 158 return m_blockSize < t.m_blockSize;
Chris@400 159 }
Chris@400 160 if (m_windowType != t.m_windowType) {
Chris@400 161 return m_windowType < t.m_windowType;
Chris@400 162 }
Chris@400 163 if (m_startTime != t.m_startTime) {
Chris@400 164 return m_startTime < t.m_startTime;
Chris@400 165 }
Chris@400 166 if (m_duration != t.m_duration) {
Chris@400 167 return m_duration < t.m_duration;
Chris@400 168 }
Chris@400 169 if (m_sampleRate != t.m_sampleRate) {
Chris@400 170 return m_sampleRate < t.m_sampleRate;
Chris@400 171 }
Chris@400 172 return false;
Chris@400 173 }
Chris@400 174
Chris@350 175 void
Chris@350 176 Transform::setIdentifier(TransformId id)
Chris@350 177 {
Chris@350 178 m_id = id;
Chris@350 179 }
Chris@350 180
Chris@350 181 TransformId
Chris@350 182 Transform::getIdentifier() const
Chris@350 183 {
Chris@350 184 return m_id;
Chris@350 185 }
Chris@350 186
Chris@328 187 QString
Chris@328 188 Transform::createIdentifier(QString type, QString soName, QString label,
Chris@328 189 QString output)
Chris@328 190 {
Chris@328 191 QString pluginId = PluginIdentifier::createIdentifier(type, soName, label);
Chris@328 192 return pluginId + ":" + output;
Chris@328 193 }
Chris@328 194
Chris@328 195 void
Chris@328 196 Transform::parseIdentifier(QString identifier,
Chris@328 197 QString &type, QString &soName,
Chris@328 198 QString &label, QString &output)
Chris@328 199 {
Chris@328 200 output = identifier.section(':', 3);
Chris@328 201 PluginIdentifier::parseIdentifier(identifier.section(':', 0, 2),
Chris@328 202 type, soName, label);
Chris@328 203 }
Chris@328 204
Chris@328 205 Transform::Type
Chris@328 206 Transform::getType() const
Chris@328 207 {
Chris@332 208 if (FeatureExtractionPluginFactory::instanceFor(getPluginIdentifier())) {
Chris@332 209 return FeatureExtraction;
Chris@332 210 } else {
Chris@332 211 // We don't have an unknown/invalid return value, so always
Chris@332 212 // return this
Chris@332 213 return RealTimeEffect;
Chris@332 214 }
Chris@328 215 }
Chris@328 216
Chris@328 217 QString
Chris@328 218 Transform::getPluginIdentifier() const
Chris@328 219 {
Chris@328 220 return m_id.section(':', 0, 2);
Chris@328 221 }
Chris@328 222
Chris@328 223 QString
Chris@328 224 Transform::getOutput() const
Chris@328 225 {
Chris@328 226 return m_id.section(':', 3);
Chris@328 227 }
Chris@328 228
Chris@353 229 void
Chris@353 230 Transform::setPluginIdentifier(QString pluginIdentifier)
Chris@353 231 {
Chris@353 232 m_id = pluginIdentifier + ':' + getOutput();
Chris@353 233 }
Chris@353 234
Chris@353 235 void
Chris@353 236 Transform::setOutput(QString output)
Chris@353 237 {
Chris@353 238 m_id = getPluginIdentifier() + ':' + output;
Chris@353 239 }
Chris@353 240
Chris@353 241 TransformId
Chris@353 242 Transform::getIdentifierForPluginOutput(QString pluginIdentifier,
Chris@353 243 QString output)
Chris@353 244 {
Chris@353 245 return pluginIdentifier + ':' + output;
Chris@353 246 }
Chris@353 247
Chris@350 248 const Transform::ParameterMap &
Chris@350 249 Transform::getParameters() const
Chris@350 250 {
Chris@350 251 return m_parameters;
Chris@350 252 }
Chris@350 253
Chris@328 254 void
Chris@350 255 Transform::setParameters(const ParameterMap &pm)
Chris@328 256 {
Chris@350 257 m_parameters = pm;
Chris@350 258 }
Chris@350 259
Chris@350 260 void
Chris@350 261 Transform::setParameter(QString name, float value)
Chris@350 262 {
Chris@403 263 // std::cerr << "Transform::setParameter(" << name.toStdString()
Chris@403 264 // << ") -> " << value << std::endl;
Chris@350 265 m_parameters[name] = value;
Chris@350 266 }
Chris@350 267
Chris@350 268 const Transform::ConfigurationMap &
Chris@350 269 Transform::getConfiguration() const
Chris@350 270 {
Chris@350 271 return m_configuration;
Chris@350 272 }
Chris@350 273
Chris@350 274 void
Chris@350 275 Transform::setConfiguration(const ConfigurationMap &cm)
Chris@350 276 {
Chris@350 277 m_configuration = cm;
Chris@350 278 }
Chris@350 279
Chris@350 280 void
Chris@350 281 Transform::setConfigurationValue(QString name, QString value)
Chris@350 282 {
Chris@350 283 std::cerr << "Transform::setConfigurationValue(" << name.toStdString()
Chris@350 284 << ") -> " << value.toStdString() << std::endl;
Chris@350 285 m_configuration[name] = value;
Chris@350 286 }
Chris@350 287
Chris@350 288 QString
Chris@366 289 Transform::getPluginVersion() const
Chris@366 290 {
Chris@366 291 return m_pluginVersion;
Chris@366 292 }
Chris@366 293
Chris@366 294 void
Chris@366 295 Transform::setPluginVersion(QString version)
Chris@366 296 {
Chris@366 297 m_pluginVersion = version;
Chris@366 298 }
Chris@366 299
Chris@366 300 QString
Chris@350 301 Transform::getProgram() const
Chris@350 302 {
Chris@350 303 return m_program;
Chris@350 304 }
Chris@350 305
Chris@350 306 void
Chris@350 307 Transform::setProgram(QString program)
Chris@350 308 {
Chris@350 309 m_program = program;
Chris@350 310 }
Chris@350 311
Chris@508 312 Transform::SummaryType
Chris@508 313 Transform::getSummaryType() const
Chris@508 314 {
Chris@508 315 return m_summaryType;
Chris@508 316 }
Chris@508 317
Chris@508 318 void
Chris@508 319 Transform::setSummaryType(SummaryType type)
Chris@508 320 {
Chris@508 321 m_summaryType = type;
Chris@508 322 }
Chris@328 323
Chris@350 324 size_t
Chris@350 325 Transform::getStepSize() const
Chris@350 326 {
Chris@350 327 return m_stepSize;
Chris@328 328 }
Chris@350 329
Chris@350 330 void
Chris@350 331 Transform::setStepSize(size_t s)
Chris@350 332 {
Chris@350 333 m_stepSize = s;
Chris@350 334 }
Chris@350 335
Chris@350 336 size_t
Chris@350 337 Transform::getBlockSize() const
Chris@350 338 {
Chris@350 339 return m_blockSize;
Chris@350 340 }
Chris@350 341
Chris@350 342 void
Chris@350 343 Transform::setBlockSize(size_t s)
Chris@350 344 {
Chris@350 345 m_blockSize = s;
Chris@350 346 }
Chris@350 347
Chris@350 348 WindowType
Chris@350 349 Transform::getWindowType() const
Chris@350 350 {
Chris@350 351 return m_windowType;
Chris@350 352 }
Chris@350 353
Chris@350 354 void
Chris@350 355 Transform::setWindowType(WindowType type)
Chris@350 356 {
Chris@350 357 m_windowType = type;
Chris@350 358 }
Chris@350 359
Chris@350 360 RealTime
Chris@350 361 Transform::getStartTime() const
Chris@350 362 {
Chris@350 363 return m_startTime;
Chris@350 364 }
Chris@350 365
Chris@350 366 void
Chris@350 367 Transform::setStartTime(RealTime t)
Chris@350 368 {
Chris@350 369 m_startTime = t;
Chris@350 370 }
Chris@350 371
Chris@350 372 RealTime
Chris@350 373 Transform::getDuration() const
Chris@350 374 {
Chris@350 375 return m_duration;
Chris@350 376 }
Chris@350 377
Chris@350 378 void
Chris@350 379 Transform::setDuration(RealTime d)
Chris@350 380 {
Chris@350 381 m_duration = d;
Chris@350 382 }
Chris@350 383
Chris@350 384 float
Chris@350 385 Transform::getSampleRate() const
Chris@350 386 {
Chris@350 387 return m_sampleRate;
Chris@350 388 }
Chris@350 389
Chris@350 390 void
Chris@350 391 Transform::setSampleRate(float rate)
Chris@350 392 {
Chris@350 393 m_sampleRate = rate;
Chris@350 394 }
Chris@350 395
Chris@350 396 void
Chris@350 397 Transform::toXml(QTextStream &out, QString indent, QString extraAttributes) const
Chris@350 398 {
Chris@350 399 out << indent;
Chris@350 400
Chris@350 401 bool haveContent = true;
Chris@350 402 if (m_parameters.empty() && m_configuration.empty()) haveContent = false;
Chris@350 403
Chris@396 404 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 405 .arg(encodeEntities(m_id))
Chris@366 406 .arg(encodeEntities(m_pluginVersion))
Chris@350 407 .arg(encodeEntities(m_program))
Chris@350 408 .arg(m_stepSize)
Chris@350 409 .arg(m_blockSize)
Chris@350 410 .arg(encodeEntities(Window<float>::getNameForType(m_windowType).c_str()))
Chris@350 411 .arg(encodeEntities(m_startTime.toString().c_str()))
Chris@350 412 .arg(encodeEntities(m_duration.toString().c_str()))
Chris@366 413 .arg(m_sampleRate);
Chris@366 414
Chris@508 415 if (m_summaryType != NoSummary) {
Chris@508 416 out << QString("\n summaryType=\"%1\"").arg(summaryTypeToString(m_summaryType));
Chris@508 417 }
Chris@508 418
Chris@366 419 if (extraAttributes != "") {
Chris@366 420 out << " " << extraAttributes;
Chris@366 421 }
Chris@350 422
Chris@350 423 if (haveContent) {
Chris@350 424
Chris@350 425 out << ">\n";
Chris@350 426
Chris@350 427 for (ParameterMap::const_iterator i = m_parameters.begin();
Chris@350 428 i != m_parameters.end(); ++i) {
Chris@350 429 out << indent << " "
Chris@350 430 << QString("<parameter name=\"%1\" value=\"%2\"/>\n")
Chris@350 431 .arg(encodeEntities(i->first))
Chris@350 432 .arg(i->second);
Chris@350 433 }
Chris@350 434
Chris@350 435 for (ConfigurationMap::const_iterator i = m_configuration.begin();
Chris@350 436 i != m_configuration.end(); ++i) {
Chris@350 437 out << indent << " "
Chris@350 438 << QString("<configuration name=\"%1\" value=\"%2\"/>\n")
Chris@350 439 .arg(encodeEntities(i->first))
Chris@350 440 .arg(encodeEntities(i->second));
Chris@350 441 }
Chris@350 442
Chris@350 443 out << indent << "</transform>\n";
Chris@350 444
Chris@350 445 } else {
Chris@350 446
Chris@350 447 out << "/>\n";
Chris@350 448 }
Chris@350 449 }
Chris@350 450
Chris@508 451 Transform::SummaryType
Chris@508 452 Transform::stringToSummaryType(QString str)
Chris@508 453 {
Chris@508 454 str = str.toLower();
Chris@508 455 if (str == "minimum" || str == "min") return Minimum;
Chris@508 456 if (str == "maximum" || str == "max") return Maximum;
Chris@508 457 if (str == "mean") return Mean;
Chris@508 458 if (str == "median") return Median;
Chris@508 459 if (str == "mode") return Mode;
Chris@508 460 if (str == "sum") return Sum;
Chris@508 461 if (str == "variance") return Variance;
Chris@508 462 if (str == "standard-deviation" || str == "standardDeviation" ||
Chris@508 463 str == "standard deviation" || str == "sd") return StandardDeviation;
Chris@508 464 if (str == "count") return Count;
Chris@508 465 if (str == "") return NoSummary;
Chris@508 466 std::cerr << "Transform::stringToSummaryType: unknown summary type \""
Chris@508 467 << str.toStdString() << "\"" << std::endl;
Chris@508 468 return NoSummary;
Chris@508 469 }
Chris@508 470
Chris@508 471 QString
Chris@508 472 Transform::summaryTypeToString(SummaryType type)
Chris@508 473 {
Chris@508 474 switch (type) {
Chris@508 475 case Minimum: return "min";
Chris@508 476 case Maximum: return "max";
Chris@508 477 case Mean: return "mean";
Chris@508 478 case Median: return "median";
Chris@508 479 case Mode: return "mode";
Chris@508 480 case Sum: return "sum";
Chris@508 481 case Variance: return "variance";
Chris@508 482 case StandardDeviation: return "sd";
Chris@508 483 case Count: return "count";
Chris@508 484 case NoSummary: return "";
Chris@508 485 default:
Chris@508 486 std::cerr << "Transform::summaryTypeToString: unexpected summary type "
Chris@508 487 << int(type) << std::endl;
Chris@508 488 return "";
Chris@508 489 }
Chris@508 490 }
Chris@508 491
Chris@350 492 void
Chris@350 493 Transform::setFromXmlAttributes(const QXmlAttributes &attrs)
Chris@350 494 {
Chris@350 495 if (attrs.value("id") != "") {
Chris@350 496 setIdentifier(attrs.value("id"));
Chris@350 497 }
Chris@350 498
Chris@366 499 if (attrs.value("pluginVersion") != "") {
Chris@366 500 setPluginVersion(attrs.value("pluginVersion"));
Chris@366 501 }
Chris@366 502
Chris@350 503 if (attrs.value("program") != "") {
Chris@350 504 setProgram(attrs.value("program"));
Chris@350 505 }
Chris@350 506
Chris@350 507 if (attrs.value("stepSize") != "") {
Chris@350 508 setStepSize(attrs.value("stepSize").toInt());
Chris@350 509 }
Chris@350 510
Chris@350 511 if (attrs.value("blockSize") != "") {
Chris@350 512 setBlockSize(attrs.value("blockSize").toInt());
Chris@350 513 }
Chris@350 514
Chris@350 515 if (attrs.value("windowType") != "") {
Chris@350 516 setWindowType(Window<float>::getTypeForName
Chris@350 517 (attrs.value("windowType").toStdString()));
Chris@350 518 }
Chris@350 519
Chris@350 520 if (attrs.value("startTime") != "") {
Chris@350 521 setStartTime(RealTime::fromString(attrs.value("startTime").toStdString()));
Chris@350 522 }
Chris@350 523
Chris@350 524 if (attrs.value("duration") != "") {
Chris@350 525 setStartTime(RealTime::fromString(attrs.value("duration").toStdString()));
Chris@350 526 }
Chris@350 527
Chris@350 528 if (attrs.value("sampleRate") != "") {
Chris@350 529 setSampleRate(attrs.value("sampleRate").toFloat());
Chris@350 530 }
Chris@508 531
Chris@508 532 if (attrs.value("summaryType") != "") {
Chris@508 533 setSummaryType(stringToSummaryType(attrs.value("summaryType")));
Chris@508 534 }
Chris@350 535 }
Chris@350 536