Chris@66: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@66: Chris@66: /* Chris@66: Sonic Visualiser Chris@66: An audio file viewer and annotation editor. Chris@66: Centre for Digital Music, Queen Mary, University of London. Chris@66: This file copyright 2006 Chris Cannam. Chris@66: Chris@66: This program is free software; you can redistribute it and/or Chris@66: modify it under the terms of the GNU General Public License as Chris@66: published by the Free Software Foundation; either version 2 of the Chris@66: License, or (at your option) any later version. See the file Chris@66: COPYING included with this distribution for more information. Chris@66: */ Chris@66: Chris@66: #include "PluginXml.h" Chris@66: Chris@66: #include Chris@66: #include Chris@66: Chris@66: #include Chris@66: #include Chris@66: #include Chris@66: #include Chris@66: Chris@314: #include Chris@314: Chris@475: #include Chris@75: #include "RealTimePluginInstance.h" Chris@66: Chris@66: #include Chris@66: Chris@1830: using std::shared_ptr; Chris@1830: using std::dynamic_pointer_cast; Chris@1830: Chris@1830: PluginXml::PluginXml(shared_ptr plugin) : Chris@66: m_plugin(plugin) Chris@66: { Chris@66: } Chris@66: Chris@66: PluginXml::~PluginXml() { } Chris@66: Chris@66: QString Chris@81: PluginXml::encodeConfigurationChars(QString text) Chris@81: { Chris@81: QString rv(text); Chris@81: rv.replace(";", "[[SEMICOLON]]"); Chris@81: rv.replace("=", "[[EQUALS]]"); Chris@81: return rv; Chris@81: } Chris@81: Chris@81: QString Chris@81: PluginXml::decodeConfigurationChars(QString text) Chris@81: { Chris@81: QString rv(text); Chris@81: rv.replace("[[SEMICOLON]]", ";"); Chris@81: rv.replace("[[EQUALS]]", "="); Chris@81: return rv; Chris@81: } Chris@81: Chris@314: void Chris@314: PluginXml::toXml(QTextStream &stream, Chris@314: QString indent, QString extraAttributes) const Chris@66: { Chris@314: stream << indent; Chris@66: Chris@314: stream << QString("getIdentifier().c_str()))) Chris@66: .arg(encodeEntities(QString(m_plugin->getName().c_str()))) Chris@66: .arg(encodeEntities(QString(m_plugin->getDescription().c_str()))) Chris@66: .arg(encodeEntities(QString(m_plugin->getMaker().c_str()))) Chris@66: .arg(m_plugin->getPluginVersion()) Chris@66: .arg(encodeEntities(QString(m_plugin->getCopyright().c_str()))) Chris@66: .arg(extraAttributes); Chris@66: Chris@66: if (!m_plugin->getPrograms().empty()) { Chris@314: stream << QString("program=\"%1\" ") Chris@66: .arg(encodeEntities(m_plugin->getCurrentProgram().c_str())); Chris@66: } Chris@66: Chris@66: Vamp::PluginBase::ParameterList parameters = Chris@66: m_plugin->getParameterDescriptors(); Chris@66: Chris@66: for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin(); Chris@66: i != parameters.end(); ++i) { Chris@185: Chris@690: // SVDEBUG << "PluginXml::toXml: parameter name \"" Chris@185: // << i->name.c_str() << "\" has value " Chris@687: // << m_plugin->getParameter(i->name) << endl; Chris@185: Chris@314: stream << QString("param-%1=\"%2\" ") Chris@239: .arg(stripInvalidParameterNameCharacters(QString(i->identifier.c_str()))) Chris@239: .arg(m_plugin->getParameter(i->identifier)); Chris@66: } Chris@66: Chris@1830: auto rtpi = dynamic_pointer_cast(m_plugin); Chris@75: if (rtpi) { Chris@75: std::map configurePairs = Chris@75: rtpi->getConfigurePairs(); Chris@75: QString config; Chris@75: for (std::map::iterator i = configurePairs.begin(); Chris@75: i != configurePairs.end(); ++i) { Chris@75: QString key = i->first.c_str(); Chris@75: QString value = i->second.c_str(); Chris@81: key = encodeConfigurationChars(key); Chris@81: value = encodeConfigurationChars(value); Chris@75: if (config != "") config += ";"; Chris@75: config += QString("%1=%2").arg(key).arg(value); Chris@75: } Chris@75: if (config != "") { Chris@314: stream << QString("configuration=\"%1\" ") Chris@75: .arg(encodeEntities(config)); Chris@75: } Chris@75: } Chris@75: Chris@314: stream << "/>\n"; Chris@66: } Chris@66: Chris@66: #define CHECK_ATTRIBUTE(ATTRIBUTE, ACCESSOR) \ Chris@66: QString ATTRIBUTE = attrs.value(#ATTRIBUTE); \ Chris@66: if (ATTRIBUTE != "" && ATTRIBUTE != ACCESSOR().c_str()) { \ Chris@843: cerr << "WARNING: PluginXml::setParameters: Plugin " \ Chris@66: << #ATTRIBUTE << " does not match (attributes have \"" \ Chris@686: << ATTRIBUTE << "\", my " \ Chris@843: << #ATTRIBUTE << " is \"" << ACCESSOR() << "\")" << endl; \ Chris@66: } Chris@66: Chris@66: void Chris@66: PluginXml::setParameters(const QXmlAttributes &attrs) Chris@66: { Chris@239: CHECK_ATTRIBUTE(identifier, m_plugin->getIdentifier); Chris@66: CHECK_ATTRIBUTE(name, m_plugin->getName); Chris@66: CHECK_ATTRIBUTE(description, m_plugin->getDescription); Chris@66: CHECK_ATTRIBUTE(maker, m_plugin->getMaker); Chris@66: CHECK_ATTRIBUTE(copyright, m_plugin->getCopyright); Chris@66: Chris@66: bool ok; Chris@66: int version = attrs.value("version").trimmed().toInt(&ok); Chris@66: if (ok && version != m_plugin->getPluginVersion()) { Chris@843: cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << endl; Chris@66: } Chris@66: Chris@1830: auto rtpi = dynamic_pointer_cast(m_plugin); Chris@75: if (rtpi) { Chris@75: QString config = attrs.value("configuration"); Chris@75: if (config != "") { Chris@75: QStringList configList = config.split(";"); Chris@75: for (QStringList::iterator i = configList.begin(); Chris@75: i != configList.end(); ++i) { Chris@75: QStringList kv = i->split("="); Chris@75: if (kv.count() < 2) { Chris@844: cerr << "WARNING: PluginXml::setParameters: Malformed configure pair string: \"" << *i << "\"" << endl; Chris@75: continue; Chris@75: } Chris@75: QString key(kv[0]), value(kv[1]); Chris@81: key = decodeConfigurationChars(key); Chris@81: value = decodeConfigurationChars(value); Chris@75: rtpi->configure(key.toStdString(), value.toStdString()); Chris@75: } Chris@75: } Chris@75: } Chris@75: Chris@66: if (!m_plugin->getPrograms().empty()) { Chris@66: m_plugin->selectProgram(attrs.value("program").toStdString()); Chris@66: } Chris@66: Chris@66: Vamp::PluginBase::ParameterList parameters = Chris@66: m_plugin->getParameterDescriptors(); Chris@66: Chris@66: for (Vamp::PluginBase::ParameterList::const_iterator i = Chris@66: parameters.begin(); i != parameters.end(); ++i) { Chris@66: Chris@239: QString pname = QString("param-%1") Chris@66: .arg(stripInvalidParameterNameCharacters Chris@239: (QString(i->identifier.c_str()))); Chris@66: Chris@239: if (attrs.value(pname) == "") { Chris@690: // SVDEBUG << "PluginXml::setParameters: no parameter \"" << i->name << "\" (attribute \"" << name << "\")" << endl; Chris@66: continue; Chris@66: } Chris@66: Chris@66: bool ok; Chris@239: float value = attrs.value(pname).trimmed().toFloat(&ok); Chris@66: if (ok) { Chris@690: // SVDEBUG << "PluginXml::setParameters: setting parameter \"" Chris@687: // << i->identifier << "\" to value " << value << endl; Chris@239: m_plugin->setParameter(i->identifier, value); Chris@66: } else { Chris@843: cerr << "WARNING: PluginXml::setParameters: Invalid value \"" << attrs.value(pname) << "\" for parameter \"" << i->identifier << "\" (attribute \"" << pname << "\")" << endl; Chris@66: } Chris@66: } Chris@66: } Chris@66: Chris@66: void Chris@66: PluginXml::setParametersFromXml(QString xml) Chris@66: { Chris@66: QDomDocument doc; Chris@66: Chris@66: QString error; Chris@66: int errorLine; Chris@66: int errorColumn; Chris@66: Chris@690: // SVDEBUG << "PluginXml::setParametersFromXml: XML is \"" Chris@845: // << xml << "\"" << endl; Chris@185: Chris@66: if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) { Chris@843: cerr << "PluginXml::setParametersFromXml: Error in parsing XML: " << error << " at line " << errorLine << ", column " << errorColumn << endl; Chris@843: cerr << "Input follows:" << endl; Chris@843: cerr << xml << endl; Chris@843: cerr << "Input ends." << endl; Chris@66: return; Chris@66: } Chris@66: Chris@66: QDomElement pluginElt = doc.firstChildElement("plugin"); Chris@66: QDomNamedNodeMap attrNodes = pluginElt.attributes(); Chris@66: QXmlAttributes attrs; Chris@66: Chris@929: for (int i = 0; i < attrNodes.length(); ++i) { Chris@66: QDomAttr attr = attrNodes.item(i).toAttr(); Chris@66: if (attr.isNull()) continue; Chris@690: // SVDEBUG << "PluginXml::setParametersFromXml: Adding attribute \"" << attr.name()// << "\" with value \"" << attr.value() << "\"" << endl; Chris@66: attrs.append(attr.name(), "", "", attr.value()); Chris@66: } Chris@66: Chris@66: setParameters(attrs); Chris@66: } Chris@163: Chris@66: QString Chris@66: PluginXml::stripInvalidParameterNameCharacters(QString s) const Chris@66: { Chris@66: s.replace(QRegExp("[^a-zA-Z0-9_]*"), ""); Chris@66: return s; Chris@66: } Chris@66: