svcore  1.9
Transform.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006-2007 Chris Cannam and QMUL.
00008    
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "Transform.h"
00017 
00018 #include "plugin/PluginIdentifier.h"
00019 
00020 #include "plugin/FeatureExtractionPluginFactory.h"
00021 
00022 #include <QXmlAttributes>
00023 
00024 #include <QDomDocument>
00025 #include <QDomElement>
00026 #include <QDomNamedNodeMap>
00027 #include <QDomAttr>
00028 
00029 #include <QTextStream>
00030 
00031 #include <iostream>
00032 
00033 Transform::Transform() :
00034     m_summaryType(NoSummary),
00035     m_stepSize(0),
00036     m_blockSize(0),
00037     m_windowType(HanningWindow),
00038     m_sampleRate(0)
00039 {
00040 }
00041 
00042 Transform::Transform(QString xml) :
00043     m_summaryType(NoSummary),
00044     m_stepSize(0),
00045     m_blockSize(0),
00046     m_windowType(HanningWindow),
00047     m_sampleRate(0)
00048 {
00049     QDomDocument doc;
00050     
00051     QString error;
00052     int errorLine;
00053     int errorColumn;
00054 
00055     if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
00056         cerr << "Transform::Transform: Error in parsing XML: "
00057                   << error << " at line " << errorLine
00058                   << ", column " << errorColumn << endl;
00059         cerr << "Input follows:" << endl;
00060         cerr << xml << endl;
00061         cerr << "Input ends." << endl;
00062         return;
00063     }
00064     
00065     QDomElement transformElt = doc.firstChildElement("transform");
00066     QDomNamedNodeMap attrNodes = transformElt.attributes();
00067     QXmlAttributes attrs;
00068 
00069     for (int i = 0; i < attrNodes.length(); ++i) {
00070         QDomAttr attr = attrNodes.item(i).toAttr();
00071         if (!attr.isNull()) attrs.append(attr.name(), "", "", attr.value());
00072     }
00073 
00074     setFromXmlAttributes(attrs);
00075 
00076     for (QDomElement paramElt = transformElt.firstChildElement("parameter");
00077          !paramElt.isNull();
00078          paramElt = paramElt.nextSiblingElement("parameter")) {
00079 
00080         QDomNamedNodeMap paramAttrs = paramElt.attributes();
00081 
00082         QDomAttr nameAttr = paramAttrs.namedItem("name").toAttr();
00083         if (nameAttr.isNull() || nameAttr.value() == "") continue;
00084         
00085         QDomAttr valueAttr = paramAttrs.namedItem("value").toAttr();
00086         if (valueAttr.isNull() || valueAttr.value() == "") continue;
00087 
00088         setParameter(nameAttr.value(), valueAttr.value().toFloat());
00089     }
00090 
00091     for (QDomElement configElt = transformElt.firstChildElement("configuration");
00092          !configElt.isNull();
00093          configElt = configElt.nextSiblingElement("configuration")) {
00094 
00095         QDomNamedNodeMap configAttrs = configElt.attributes();
00096 
00097         QDomAttr nameAttr = configAttrs.namedItem("name").toAttr();
00098         if (nameAttr.isNull() || nameAttr.value() == "") continue;
00099         
00100         QDomAttr valueAttr = configAttrs.namedItem("value").toAttr();
00101         if (valueAttr.isNull() || valueAttr.value() == "") continue;
00102 
00103         setConfigurationValue(nameAttr.value(), valueAttr.value());
00104     }
00105 }
00106 
00107 Transform::~Transform()
00108 {
00109 }
00110 
00111 bool
00112 Transform::operator==(const Transform &t) const
00113 {
00114     bool identical =  
00115         m_id == t.m_id &&
00116         m_parameters == t.m_parameters &&
00117         m_configuration == t.m_configuration &&
00118         m_program == t.m_program &&
00119         m_summaryType == t.m_summaryType &&
00120         m_stepSize == t.m_stepSize &&
00121         m_blockSize == t.m_blockSize &&
00122         m_windowType == t.m_windowType &&
00123         m_startTime == t.m_startTime &&
00124         m_duration == t.m_duration &&
00125         m_sampleRate == t.m_sampleRate;
00126 /*
00127     SVDEBUG << "Transform::operator==: identical = " << identical << endl;
00128     cerr << "A = " << endl;
00129     cerr << toXmlString() << endl;
00130     cerr << "B = " << endl;
00131     cerr << t.toXmlString() << endl;
00132 */
00133     return identical;
00134 }
00135 
00136 bool
00137 Transform::operator<(const Transform &t) const
00138 {
00139     if (m_id != t.m_id) {
00140         return m_id < t.m_id;
00141     }
00142     if (m_parameters != t.m_parameters) {
00143         return mapLessThan<QString, float>(m_parameters, t.m_parameters);
00144     }
00145     if (m_configuration != t.m_configuration) {
00146         return mapLessThan<QString, QString>(m_configuration, t.m_configuration);
00147     }
00148     if (m_program != t.m_program) {
00149         return m_program < t.m_program;
00150     }
00151     if (m_summaryType != t.m_summaryType) {
00152         return int(m_summaryType) < int(t.m_summaryType);
00153     }
00154     if (m_stepSize != t.m_stepSize) {
00155         return m_stepSize < t.m_stepSize;
00156     }
00157     if (m_blockSize != t.m_blockSize) {
00158         return m_blockSize < t.m_blockSize;
00159     }
00160     if (m_windowType != t.m_windowType) {
00161         return m_windowType < t.m_windowType;
00162     }
00163     if (m_startTime != t.m_startTime) {
00164         return m_startTime < t.m_startTime;
00165     }
00166     if (m_duration != t.m_duration) {
00167         return m_duration < t.m_duration;
00168     }
00169     if (m_sampleRate != t.m_sampleRate) {
00170         return m_sampleRate < t.m_sampleRate;
00171     }
00172     return false;
00173 }
00174 
00175 void
00176 Transform::setIdentifier(TransformId id)
00177 {
00178     m_id = id;
00179 }
00180 
00181 TransformId
00182 Transform::getIdentifier() const
00183 {
00184     return m_id;
00185 }
00186 
00187 QString
00188 Transform::createIdentifier(QString type, QString soName, QString label,
00189                             QString output)
00190 {
00191     QString pluginId = PluginIdentifier::createIdentifier(type, soName, label);
00192     return pluginId + ":" + output;
00193 }
00194 
00195 void
00196 Transform::parseIdentifier(QString identifier,
00197                            QString &type, QString &soName,
00198                            QString &label, QString &output)
00199 {
00200     output = identifier.section(':', 3);
00201     PluginIdentifier::parseIdentifier(identifier.section(':', 0, 2),
00202                                       type, soName, label);
00203 }
00204 
00205 Transform::Type
00206 Transform::getType() const
00207 {
00208     if (FeatureExtractionPluginFactory::instanceFor(getPluginIdentifier())) {
00209         return FeatureExtraction;
00210     } else {
00211         // We don't have an unknown/invalid return value, so always
00212         // return this
00213         return RealTimeEffect;
00214     }
00215 }
00216 
00217 QString
00218 Transform::getPluginIdentifier() const
00219 {
00220     return m_id.section(':', 0, 2);
00221 }
00222 
00223 QString
00224 Transform::getOutput() const
00225 {
00226     return m_id.section(':', 3);
00227 }
00228 
00229 void
00230 Transform::setPluginIdentifier(QString pluginIdentifier)
00231 {
00232     m_id = pluginIdentifier + ':' + getOutput();
00233 }
00234 
00235 void
00236 Transform::setOutput(QString output)
00237 {
00238     m_id = getPluginIdentifier() + ':' + output;
00239 }
00240 
00241 TransformId
00242 Transform::getIdentifierForPluginOutput(QString pluginIdentifier,
00243                                         QString output)
00244 {
00245     return pluginIdentifier + ':' + output;
00246 }
00247 
00248 const Transform::ParameterMap &
00249 Transform::getParameters() const
00250 {
00251     return m_parameters;
00252 }
00253 
00254 void
00255 Transform::setParameters(const ParameterMap &pm)
00256 {
00257     m_parameters = pm;
00258 }
00259 
00260 void
00261 Transform::setParameter(QString name, float value)
00262 {
00263 //    SVDEBUG << "Transform::setParameter(" << name//              << ") -> " << value << endl;
00264     m_parameters[name] = value;
00265 }
00266 
00267 const Transform::ConfigurationMap &
00268 Transform::getConfiguration() const
00269 {
00270     return m_configuration;
00271 }
00272 
00273 void
00274 Transform::setConfiguration(const ConfigurationMap &cm)
00275 {
00276     m_configuration = cm;
00277 }
00278 
00279 void
00280 Transform::setConfigurationValue(QString name, QString value)
00281 {
00282     SVDEBUG << "Transform::setConfigurationValue(" << name              << ") -> " << value << endl;
00283     m_configuration[name] = value;
00284 }
00285 
00286 QString
00287 Transform::getPluginVersion() const
00288 {
00289     return m_pluginVersion;
00290 }
00291 
00292 void
00293 Transform::setPluginVersion(QString version)
00294 {
00295     m_pluginVersion = version;
00296 }
00297 
00298 QString
00299 Transform::getProgram() const
00300 {
00301     return m_program;
00302 }
00303 
00304 void
00305 Transform::setProgram(QString program)
00306 {
00307     m_program = program;
00308 }
00309 
00310 Transform::SummaryType
00311 Transform::getSummaryType() const
00312 {
00313     return m_summaryType;
00314 }
00315 
00316 void
00317 Transform::setSummaryType(SummaryType type)
00318 {
00319     m_summaryType = type;
00320 }
00321     
00322 int
00323 Transform::getStepSize() const
00324 {
00325     return m_stepSize;
00326 }
00327 
00328 void
00329 Transform::setStepSize(int s)
00330 {
00331     m_stepSize = s;
00332 }
00333     
00334 int
00335 Transform::getBlockSize() const
00336 {
00337     return m_blockSize;
00338 }
00339 
00340 void
00341 Transform::setBlockSize(int s)
00342 {
00343     m_blockSize = s;
00344 }
00345 
00346 WindowType
00347 Transform::getWindowType() const
00348 {
00349     return m_windowType;
00350 }
00351 
00352 void
00353 Transform::setWindowType(WindowType type)
00354 {
00355     m_windowType = type;
00356 }
00357 
00358 RealTime
00359 Transform::getStartTime() const
00360 {
00361     return m_startTime;
00362 }
00363 
00364 void
00365 Transform::setStartTime(RealTime t)
00366 {
00367     m_startTime = t;
00368 }
00369 
00370 RealTime
00371 Transform::getDuration() const
00372 {
00373     return m_duration;
00374 }
00375 
00376 void
00377 Transform::setDuration(RealTime d)
00378 {
00379     m_duration = d;
00380 }
00381     
00382 float
00383 Transform::getSampleRate() const
00384 {
00385     return m_sampleRate;
00386 }
00387 
00388 void
00389 Transform::setSampleRate(float rate)
00390 {
00391     m_sampleRate = rate;
00392 }
00393 
00394 void
00395 Transform::toXml(QTextStream &out, QString indent, QString extraAttributes) const
00396 {
00397     out << indent;
00398 
00399     bool haveContent = true;
00400     if (m_parameters.empty() && m_configuration.empty()) haveContent = false;
00401 
00402     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\"")
00403         .arg(encodeEntities(m_id))
00404         .arg(encodeEntities(m_pluginVersion))
00405         .arg(encodeEntities(m_program))
00406         .arg(m_stepSize)
00407         .arg(m_blockSize)
00408         .arg(encodeEntities(Window<float>::getNameForType(m_windowType).c_str()))
00409         .arg(encodeEntities(m_startTime.toString().c_str()))
00410         .arg(encodeEntities(m_duration.toString().c_str()))
00411         .arg(m_sampleRate);
00412 
00413     if (m_summaryType != NoSummary) {
00414         out << QString("\n    summaryType=\"%1\"").arg(summaryTypeToString(m_summaryType));
00415     }
00416 
00417     if (extraAttributes != "") {
00418         out << " " << extraAttributes;
00419     }
00420 
00421     if (haveContent) {
00422 
00423         out << ">\n";
00424 
00425         for (ParameterMap::const_iterator i = m_parameters.begin();
00426              i != m_parameters.end(); ++i) {
00427             out << indent << "  "
00428                 << QString("<parameter name=\"%1\" value=\"%2\"/>\n")
00429                 .arg(encodeEntities(i->first))
00430                 .arg(i->second);
00431         }
00432         
00433         for (ConfigurationMap::const_iterator i = m_configuration.begin();
00434              i != m_configuration.end(); ++i) {
00435             out << indent << "  "
00436                 << QString("<configuration name=\"%1\" value=\"%2\"/>\n")
00437                 .arg(encodeEntities(i->first))
00438                 .arg(encodeEntities(i->second));
00439         }
00440 
00441         out << indent << "</transform>\n";
00442 
00443     } else {
00444 
00445         out << "/>\n";
00446     }
00447 }
00448 
00449 Transform::SummaryType
00450 Transform::stringToSummaryType(QString str)
00451 {
00452     str = str.toLower();
00453     if (str == "minimum" || str == "min") return Minimum;
00454     if (str == "maximum" || str == "max") return Maximum;
00455     if (str == "mean") return Mean;
00456     if (str == "median") return Median;
00457     if (str == "mode") return Mode;
00458     if (str == "sum") return Sum;
00459     if (str == "variance") return Variance;
00460     if (str == "standard-deviation" || str == "standardDeviation" ||
00461         str == "standard deviation" || str == "sd") return StandardDeviation;
00462     if (str == "count") return Count;
00463     if (str == "") return NoSummary;
00464     SVDEBUG << "Transform::stringToSummaryType: unknown summary type \""
00465               << str << "\"" << endl;
00466     return NoSummary;
00467 }
00468 
00469 QString
00470 Transform::summaryTypeToString(SummaryType type)
00471 {
00472     switch (type) {
00473     case Minimum: return "min";
00474     case Maximum: return "max";
00475     case Mean: return "mean";
00476     case Median: return "median";
00477     case Mode: return "mode";
00478     case Sum: return "sum";
00479     case Variance: return "variance";
00480     case StandardDeviation: return "sd";
00481     case Count: return "count";
00482     case NoSummary: return "";
00483     default:
00484         SVDEBUG << "Transform::summaryTypeToString: unexpected summary type "
00485                   << int(type) << endl;
00486         return "";
00487     }
00488 }
00489 
00490 void
00491 Transform::setFromXmlAttributes(const QXmlAttributes &attrs)
00492 {
00493     if (attrs.value("id") != "") {
00494         setIdentifier(attrs.value("id"));
00495     }
00496 
00497     if (attrs.value("pluginVersion") != "") {
00498         setPluginVersion(attrs.value("pluginVersion"));
00499     }
00500 
00501     if (attrs.value("program") != "") {
00502         setProgram(attrs.value("program"));
00503     }
00504 
00505     if (attrs.value("stepSize") != "") {
00506         setStepSize(attrs.value("stepSize").toInt());
00507     }
00508 
00509     if (attrs.value("blockSize") != "") {
00510         setBlockSize(attrs.value("blockSize").toInt());
00511     }
00512 
00513     if (attrs.value("windowType") != "") {
00514         setWindowType(Window<float>::getTypeForName
00515                       (attrs.value("windowType").toStdString()));
00516     }
00517 
00518     if (attrs.value("startTime") != "") {
00519         setStartTime(RealTime::fromString(attrs.value("startTime").toStdString()));
00520     }
00521 
00522     if (attrs.value("duration") != "") {
00523         setStartTime(RealTime::fromString(attrs.value("duration").toStdString()));
00524     }
00525     
00526     if (attrs.value("sampleRate") != "") {
00527         setSampleRate(attrs.value("sampleRate").toFloat());
00528     }
00529 
00530     if (attrs.value("summaryType") != "") {
00531         setSummaryType(stringToSummaryType(attrs.value("summaryType")));
00532     }
00533 }
00534