annotate plugin/PluginXml.cpp @ 1881:b504df98c3be

Ensure completion on output model is started at zero, so if it's checked before the input model has become ready and the transform has begun, it is not accidentally reported as complete (affected re-aligning models in Sonic Lineup when replacing the session)
author Chris Cannam
date Fri, 26 Jun 2020 11:45:39 +0100
parents 5f8fbbde08ff
children
rev   line source
Chris@66 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@66 2
Chris@66 3 /*
Chris@66 4 Sonic Visualiser
Chris@66 5 An audio file viewer and annotation editor.
Chris@66 6 Centre for Digital Music, Queen Mary, University of London.
Chris@66 7 This file copyright 2006 Chris Cannam.
Chris@66 8
Chris@66 9 This program is free software; you can redistribute it and/or
Chris@66 10 modify it under the terms of the GNU General Public License as
Chris@66 11 published by the Free Software Foundation; either version 2 of the
Chris@66 12 License, or (at your option) any later version. See the file
Chris@66 13 COPYING included with this distribution for more information.
Chris@66 14 */
Chris@66 15
Chris@66 16 #include "PluginXml.h"
Chris@66 17
Chris@66 18 #include <QRegExp>
Chris@66 19 #include <QXmlAttributes>
Chris@66 20
Chris@66 21 #include <QDomDocument>
Chris@66 22 #include <QDomElement>
Chris@66 23 #include <QDomNamedNodeMap>
Chris@66 24 #include <QDomAttr>
Chris@66 25
Chris@314 26 #include <QTextStream>
Chris@314 27
Chris@475 28 #include <vamp-hostsdk/PluginBase.h>
Chris@75 29 #include "RealTimePluginInstance.h"
Chris@66 30
Chris@66 31 #include <iostream>
Chris@66 32
Chris@1830 33 using std::shared_ptr;
Chris@1830 34 using std::dynamic_pointer_cast;
Chris@1830 35
Chris@1830 36 PluginXml::PluginXml(shared_ptr<Vamp::PluginBase> plugin) :
Chris@66 37 m_plugin(plugin)
Chris@66 38 {
Chris@66 39 }
Chris@66 40
Chris@66 41 PluginXml::~PluginXml() { }
Chris@66 42
Chris@66 43 QString
Chris@81 44 PluginXml::encodeConfigurationChars(QString text)
Chris@81 45 {
Chris@81 46 QString rv(text);
Chris@81 47 rv.replace(";", "[[SEMICOLON]]");
Chris@81 48 rv.replace("=", "[[EQUALS]]");
Chris@81 49 return rv;
Chris@81 50 }
Chris@81 51
Chris@81 52 QString
Chris@81 53 PluginXml::decodeConfigurationChars(QString text)
Chris@81 54 {
Chris@81 55 QString rv(text);
Chris@81 56 rv.replace("[[SEMICOLON]]", ";");
Chris@81 57 rv.replace("[[EQUALS]]", "=");
Chris@81 58 return rv;
Chris@81 59 }
Chris@81 60
Chris@314 61 void
Chris@314 62 PluginXml::toXml(QTextStream &stream,
Chris@314 63 QString indent, QString extraAttributes) const
Chris@66 64 {
Chris@314 65 stream << indent;
Chris@66 66
Chris@314 67 stream << QString("<plugin identifier=\"%1\" name=\"%2\" description=\"%3\" maker=\"%4\" version=\"%5\" copyright=\"%6\" %7 ")
Chris@239 68 .arg(encodeEntities(QString(m_plugin->getIdentifier().c_str())))
Chris@66 69 .arg(encodeEntities(QString(m_plugin->getName().c_str())))
Chris@66 70 .arg(encodeEntities(QString(m_plugin->getDescription().c_str())))
Chris@66 71 .arg(encodeEntities(QString(m_plugin->getMaker().c_str())))
Chris@66 72 .arg(m_plugin->getPluginVersion())
Chris@66 73 .arg(encodeEntities(QString(m_plugin->getCopyright().c_str())))
Chris@66 74 .arg(extraAttributes);
Chris@66 75
Chris@66 76 if (!m_plugin->getPrograms().empty()) {
Chris@314 77 stream << QString("program=\"%1\" ")
Chris@66 78 .arg(encodeEntities(m_plugin->getCurrentProgram().c_str()));
Chris@66 79 }
Chris@66 80
Chris@66 81 Vamp::PluginBase::ParameterList parameters =
Chris@66 82 m_plugin->getParameterDescriptors();
Chris@66 83
Chris@66 84 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
Chris@66 85 i != parameters.end(); ++i) {
Chris@185 86
Chris@690 87 // SVDEBUG << "PluginXml::toXml: parameter name \""
Chris@185 88 // << i->name.c_str() << "\" has value "
Chris@687 89 // << m_plugin->getParameter(i->name) << endl;
Chris@185 90
Chris@314 91 stream << QString("param-%1=\"%2\" ")
Chris@239 92 .arg(stripInvalidParameterNameCharacters(QString(i->identifier.c_str())))
Chris@239 93 .arg(m_plugin->getParameter(i->identifier));
Chris@66 94 }
Chris@66 95
Chris@1830 96 auto rtpi = dynamic_pointer_cast<RealTimePluginInstance>(m_plugin);
Chris@75 97 if (rtpi) {
Chris@75 98 std::map<std::string, std::string> configurePairs =
Chris@75 99 rtpi->getConfigurePairs();
Chris@75 100 QString config;
Chris@75 101 for (std::map<std::string, std::string>::iterator i = configurePairs.begin();
Chris@75 102 i != configurePairs.end(); ++i) {
Chris@75 103 QString key = i->first.c_str();
Chris@75 104 QString value = i->second.c_str();
Chris@81 105 key = encodeConfigurationChars(key);
Chris@81 106 value = encodeConfigurationChars(value);
Chris@75 107 if (config != "") config += ";";
Chris@75 108 config += QString("%1=%2").arg(key).arg(value);
Chris@75 109 }
Chris@75 110 if (config != "") {
Chris@314 111 stream << QString("configuration=\"%1\" ")
Chris@75 112 .arg(encodeEntities(config));
Chris@75 113 }
Chris@75 114 }
Chris@75 115
Chris@314 116 stream << "/>\n";
Chris@66 117 }
Chris@66 118
Chris@66 119 #define CHECK_ATTRIBUTE(ATTRIBUTE, ACCESSOR) \
Chris@66 120 QString ATTRIBUTE = attrs.value(#ATTRIBUTE); \
Chris@66 121 if (ATTRIBUTE != "" && ATTRIBUTE != ACCESSOR().c_str()) { \
Chris@843 122 cerr << "WARNING: PluginXml::setParameters: Plugin " \
Chris@66 123 << #ATTRIBUTE << " does not match (attributes have \"" \
Chris@686 124 << ATTRIBUTE << "\", my " \
Chris@843 125 << #ATTRIBUTE << " is \"" << ACCESSOR() << "\")" << endl; \
Chris@66 126 }
Chris@66 127
Chris@66 128 void
Chris@66 129 PluginXml::setParameters(const QXmlAttributes &attrs)
Chris@66 130 {
Chris@239 131 CHECK_ATTRIBUTE(identifier, m_plugin->getIdentifier);
Chris@66 132 CHECK_ATTRIBUTE(name, m_plugin->getName);
Chris@66 133 CHECK_ATTRIBUTE(description, m_plugin->getDescription);
Chris@66 134 CHECK_ATTRIBUTE(maker, m_plugin->getMaker);
Chris@66 135 CHECK_ATTRIBUTE(copyright, m_plugin->getCopyright);
Chris@66 136
Chris@66 137 bool ok;
Chris@66 138 int version = attrs.value("version").trimmed().toInt(&ok);
Chris@66 139 if (ok && version != m_plugin->getPluginVersion()) {
Chris@843 140 cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << endl;
Chris@66 141 }
Chris@66 142
Chris@1830 143 auto rtpi = dynamic_pointer_cast<RealTimePluginInstance>(m_plugin);
Chris@75 144 if (rtpi) {
Chris@75 145 QString config = attrs.value("configuration");
Chris@75 146 if (config != "") {
Chris@75 147 QStringList configList = config.split(";");
Chris@75 148 for (QStringList::iterator i = configList.begin();
Chris@75 149 i != configList.end(); ++i) {
Chris@75 150 QStringList kv = i->split("=");
Chris@75 151 if (kv.count() < 2) {
Chris@844 152 cerr << "WARNING: PluginXml::setParameters: Malformed configure pair string: \"" << *i << "\"" << endl;
Chris@75 153 continue;
Chris@75 154 }
Chris@75 155 QString key(kv[0]), value(kv[1]);
Chris@81 156 key = decodeConfigurationChars(key);
Chris@81 157 value = decodeConfigurationChars(value);
Chris@75 158 rtpi->configure(key.toStdString(), value.toStdString());
Chris@75 159 }
Chris@75 160 }
Chris@75 161 }
Chris@75 162
Chris@66 163 if (!m_plugin->getPrograms().empty()) {
Chris@66 164 m_plugin->selectProgram(attrs.value("program").toStdString());
Chris@66 165 }
Chris@66 166
Chris@66 167 Vamp::PluginBase::ParameterList parameters =
Chris@66 168 m_plugin->getParameterDescriptors();
Chris@66 169
Chris@66 170 for (Vamp::PluginBase::ParameterList::const_iterator i =
Chris@66 171 parameters.begin(); i != parameters.end(); ++i) {
Chris@66 172
Chris@239 173 QString pname = QString("param-%1")
Chris@66 174 .arg(stripInvalidParameterNameCharacters
Chris@239 175 (QString(i->identifier.c_str())));
Chris@66 176
Chris@239 177 if (attrs.value(pname) == "") {
Chris@690 178 // SVDEBUG << "PluginXml::setParameters: no parameter \"" << i->name << "\" (attribute \"" << name << "\")" << endl;
Chris@66 179 continue;
Chris@66 180 }
Chris@66 181
Chris@66 182 bool ok;
Chris@239 183 float value = attrs.value(pname).trimmed().toFloat(&ok);
Chris@66 184 if (ok) {
Chris@690 185 // SVDEBUG << "PluginXml::setParameters: setting parameter \""
Chris@687 186 // << i->identifier << "\" to value " << value << endl;
Chris@239 187 m_plugin->setParameter(i->identifier, value);
Chris@66 188 } else {
Chris@843 189 cerr << "WARNING: PluginXml::setParameters: Invalid value \"" << attrs.value(pname) << "\" for parameter \"" << i->identifier << "\" (attribute \"" << pname << "\")" << endl;
Chris@66 190 }
Chris@66 191 }
Chris@66 192 }
Chris@66 193
Chris@66 194 void
Chris@66 195 PluginXml::setParametersFromXml(QString xml)
Chris@66 196 {
Chris@66 197 QDomDocument doc;
Chris@66 198
Chris@66 199 QString error;
Chris@66 200 int errorLine;
Chris@66 201 int errorColumn;
Chris@66 202
Chris@690 203 // SVDEBUG << "PluginXml::setParametersFromXml: XML is \""
Chris@845 204 // << xml << "\"" << endl;
Chris@185 205
Chris@66 206 if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
Chris@843 207 cerr << "PluginXml::setParametersFromXml: Error in parsing XML: " << error << " at line " << errorLine << ", column " << errorColumn << endl;
Chris@843 208 cerr << "Input follows:" << endl;
Chris@843 209 cerr << xml << endl;
Chris@843 210 cerr << "Input ends." << endl;
Chris@66 211 return;
Chris@66 212 }
Chris@66 213
Chris@66 214 QDomElement pluginElt = doc.firstChildElement("plugin");
Chris@66 215 QDomNamedNodeMap attrNodes = pluginElt.attributes();
Chris@66 216 QXmlAttributes attrs;
Chris@66 217
Chris@929 218 for (int i = 0; i < attrNodes.length(); ++i) {
Chris@66 219 QDomAttr attr = attrNodes.item(i).toAttr();
Chris@66 220 if (attr.isNull()) continue;
Chris@690 221 // SVDEBUG << "PluginXml::setParametersFromXml: Adding attribute \"" << attr.name()// << "\" with value \"" << attr.value() << "\"" << endl;
Chris@66 222 attrs.append(attr.name(), "", "", attr.value());
Chris@66 223 }
Chris@66 224
Chris@66 225 setParameters(attrs);
Chris@66 226 }
Chris@163 227
Chris@66 228 QString
Chris@66 229 PluginXml::stripInvalidParameterNameCharacters(QString s) const
Chris@66 230 {
Chris@66 231 s.replace(QRegExp("[^a-zA-Z0-9_]*"), "");
Chris@66 232 return s;
Chris@66 233 }
Chris@66 234