annotate transform/Transform.cpp @ 1196:c7b9c902642f spectrogram-minor-refactor

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