annotate plugin/PluginXml.cpp @ 1288:5ef9b4d4bbdb 3.0-integration

Filter out Xing/LAME info frames, rather than letting them go to the mp3 decoder as if they were audio frames. Fixes the 1152-sample zero pad at start of some decoded mp3 files (distinct from decoder delay). The logic here is based on the madplay code.
author Chris Cannam
date Thu, 24 Nov 2016 13:32:04 +0000
parents 59e7fe1b1003
children 5f8fbbde08ff
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@66 33 PluginXml::PluginXml(Vamp::PluginBase *plugin) :
Chris@66 34 m_plugin(plugin)
Chris@66 35 {
Chris@66 36 }
Chris@66 37
Chris@66 38 PluginXml::~PluginXml() { }
Chris@66 39
Chris@66 40 QString
Chris@81 41 PluginXml::encodeConfigurationChars(QString text)
Chris@81 42 {
Chris@81 43 QString rv(text);
Chris@81 44 rv.replace(";", "[[SEMICOLON]]");
Chris@81 45 rv.replace("=", "[[EQUALS]]");
Chris@81 46 return rv;
Chris@81 47 }
Chris@81 48
Chris@81 49 QString
Chris@81 50 PluginXml::decodeConfigurationChars(QString text)
Chris@81 51 {
Chris@81 52 QString rv(text);
Chris@81 53 rv.replace("[[SEMICOLON]]", ";");
Chris@81 54 rv.replace("[[EQUALS]]", "=");
Chris@81 55 return rv;
Chris@81 56 }
Chris@81 57
Chris@314 58 void
Chris@314 59 PluginXml::toXml(QTextStream &stream,
Chris@314 60 QString indent, QString extraAttributes) const
Chris@66 61 {
Chris@314 62 stream << indent;
Chris@66 63
Chris@314 64 stream << QString("<plugin identifier=\"%1\" name=\"%2\" description=\"%3\" maker=\"%4\" version=\"%5\" copyright=\"%6\" %7 ")
Chris@239 65 .arg(encodeEntities(QString(m_plugin->getIdentifier().c_str())))
Chris@66 66 .arg(encodeEntities(QString(m_plugin->getName().c_str())))
Chris@66 67 .arg(encodeEntities(QString(m_plugin->getDescription().c_str())))
Chris@66 68 .arg(encodeEntities(QString(m_plugin->getMaker().c_str())))
Chris@66 69 .arg(m_plugin->getPluginVersion())
Chris@66 70 .arg(encodeEntities(QString(m_plugin->getCopyright().c_str())))
Chris@66 71 .arg(extraAttributes);
Chris@66 72
Chris@66 73 if (!m_plugin->getPrograms().empty()) {
Chris@314 74 stream << QString("program=\"%1\" ")
Chris@66 75 .arg(encodeEntities(m_plugin->getCurrentProgram().c_str()));
Chris@66 76 }
Chris@66 77
Chris@66 78 Vamp::PluginBase::ParameterList parameters =
Chris@66 79 m_plugin->getParameterDescriptors();
Chris@66 80
Chris@66 81 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
Chris@66 82 i != parameters.end(); ++i) {
Chris@185 83
Chris@690 84 // SVDEBUG << "PluginXml::toXml: parameter name \""
Chris@185 85 // << i->name.c_str() << "\" has value "
Chris@687 86 // << m_plugin->getParameter(i->name) << endl;
Chris@185 87
Chris@314 88 stream << QString("param-%1=\"%2\" ")
Chris@239 89 .arg(stripInvalidParameterNameCharacters(QString(i->identifier.c_str())))
Chris@239 90 .arg(m_plugin->getParameter(i->identifier));
Chris@66 91 }
Chris@66 92
Chris@75 93 RealTimePluginInstance *rtpi =
Chris@75 94 dynamic_cast<RealTimePluginInstance *>(m_plugin);
Chris@75 95 if (rtpi) {
Chris@75 96 std::map<std::string, std::string> configurePairs =
Chris@75 97 rtpi->getConfigurePairs();
Chris@75 98 QString config;
Chris@75 99 for (std::map<std::string, std::string>::iterator i = configurePairs.begin();
Chris@75 100 i != configurePairs.end(); ++i) {
Chris@75 101 QString key = i->first.c_str();
Chris@75 102 QString value = i->second.c_str();
Chris@81 103 key = encodeConfigurationChars(key);
Chris@81 104 value = encodeConfigurationChars(value);
Chris@75 105 if (config != "") config += ";";
Chris@75 106 config += QString("%1=%2").arg(key).arg(value);
Chris@75 107 }
Chris@75 108 if (config != "") {
Chris@314 109 stream << QString("configuration=\"%1\" ")
Chris@75 110 .arg(encodeEntities(config));
Chris@75 111 }
Chris@75 112 }
Chris@75 113
Chris@314 114 stream << "/>\n";
Chris@66 115 }
Chris@66 116
Chris@66 117 #define CHECK_ATTRIBUTE(ATTRIBUTE, ACCESSOR) \
Chris@66 118 QString ATTRIBUTE = attrs.value(#ATTRIBUTE); \
Chris@66 119 if (ATTRIBUTE != "" && ATTRIBUTE != ACCESSOR().c_str()) { \
Chris@843 120 cerr << "WARNING: PluginXml::setParameters: Plugin " \
Chris@66 121 << #ATTRIBUTE << " does not match (attributes have \"" \
Chris@686 122 << ATTRIBUTE << "\", my " \
Chris@843 123 << #ATTRIBUTE << " is \"" << ACCESSOR() << "\")" << endl; \
Chris@66 124 }
Chris@66 125
Chris@66 126 void
Chris@66 127 PluginXml::setParameters(const QXmlAttributes &attrs)
Chris@66 128 {
Chris@239 129 CHECK_ATTRIBUTE(identifier, m_plugin->getIdentifier);
Chris@66 130 CHECK_ATTRIBUTE(name, m_plugin->getName);
Chris@66 131 CHECK_ATTRIBUTE(description, m_plugin->getDescription);
Chris@66 132 CHECK_ATTRIBUTE(maker, m_plugin->getMaker);
Chris@66 133 CHECK_ATTRIBUTE(copyright, m_plugin->getCopyright);
Chris@66 134
Chris@66 135 bool ok;
Chris@66 136 int version = attrs.value("version").trimmed().toInt(&ok);
Chris@66 137 if (ok && version != m_plugin->getPluginVersion()) {
Chris@843 138 cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << endl;
Chris@66 139 }
Chris@66 140
Chris@75 141 RealTimePluginInstance *rtpi =
Chris@75 142 dynamic_cast<RealTimePluginInstance *>(m_plugin);
Chris@75 143 if (rtpi) {
Chris@75 144 QString config = attrs.value("configuration");
Chris@75 145 if (config != "") {
Chris@75 146 QStringList configList = config.split(";");
Chris@75 147 for (QStringList::iterator i = configList.begin();
Chris@75 148 i != configList.end(); ++i) {
Chris@75 149 QStringList kv = i->split("=");
Chris@75 150 if (kv.count() < 2) {
Chris@844 151 cerr << "WARNING: PluginXml::setParameters: Malformed configure pair string: \"" << *i << "\"" << endl;
Chris@75 152 continue;
Chris@75 153 }
Chris@75 154 QString key(kv[0]), value(kv[1]);
Chris@81 155 key = decodeConfigurationChars(key);
Chris@81 156 value = decodeConfigurationChars(value);
Chris@75 157 rtpi->configure(key.toStdString(), value.toStdString());
Chris@75 158 }
Chris@75 159 }
Chris@75 160 }
Chris@75 161
Chris@66 162 if (!m_plugin->getPrograms().empty()) {
Chris@66 163 m_plugin->selectProgram(attrs.value("program").toStdString());
Chris@66 164 }
Chris@66 165
Chris@66 166 Vamp::PluginBase::ParameterList parameters =
Chris@66 167 m_plugin->getParameterDescriptors();
Chris@66 168
Chris@66 169 for (Vamp::PluginBase::ParameterList::const_iterator i =
Chris@66 170 parameters.begin(); i != parameters.end(); ++i) {
Chris@66 171
Chris@239 172 QString pname = QString("param-%1")
Chris@66 173 .arg(stripInvalidParameterNameCharacters
Chris@239 174 (QString(i->identifier.c_str())));
Chris@66 175
Chris@239 176 if (attrs.value(pname) == "") {
Chris@690 177 // SVDEBUG << "PluginXml::setParameters: no parameter \"" << i->name << "\" (attribute \"" << name << "\")" << endl;
Chris@66 178 continue;
Chris@66 179 }
Chris@66 180
Chris@66 181 bool ok;
Chris@239 182 float value = attrs.value(pname).trimmed().toFloat(&ok);
Chris@66 183 if (ok) {
Chris@690 184 // SVDEBUG << "PluginXml::setParameters: setting parameter \""
Chris@687 185 // << i->identifier << "\" to value " << value << endl;
Chris@239 186 m_plugin->setParameter(i->identifier, value);
Chris@66 187 } else {
Chris@843 188 cerr << "WARNING: PluginXml::setParameters: Invalid value \"" << attrs.value(pname) << "\" for parameter \"" << i->identifier << "\" (attribute \"" << pname << "\")" << endl;
Chris@66 189 }
Chris@66 190 }
Chris@66 191 }
Chris@66 192
Chris@66 193 void
Chris@66 194 PluginXml::setParametersFromXml(QString xml)
Chris@66 195 {
Chris@66 196 QDomDocument doc;
Chris@66 197
Chris@66 198 QString error;
Chris@66 199 int errorLine;
Chris@66 200 int errorColumn;
Chris@66 201
Chris@690 202 // SVDEBUG << "PluginXml::setParametersFromXml: XML is \""
Chris@845 203 // << xml << "\"" << endl;
Chris@185 204
Chris@66 205 if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
Chris@843 206 cerr << "PluginXml::setParametersFromXml: Error in parsing XML: " << error << " at line " << errorLine << ", column " << errorColumn << endl;
Chris@843 207 cerr << "Input follows:" << endl;
Chris@843 208 cerr << xml << endl;
Chris@843 209 cerr << "Input ends." << endl;
Chris@66 210 return;
Chris@66 211 }
Chris@66 212
Chris@66 213 QDomElement pluginElt = doc.firstChildElement("plugin");
Chris@66 214 QDomNamedNodeMap attrNodes = pluginElt.attributes();
Chris@66 215 QXmlAttributes attrs;
Chris@66 216
Chris@929 217 for (int i = 0; i < attrNodes.length(); ++i) {
Chris@66 218 QDomAttr attr = attrNodes.item(i).toAttr();
Chris@66 219 if (attr.isNull()) continue;
Chris@690 220 // SVDEBUG << "PluginXml::setParametersFromXml: Adding attribute \"" << attr.name()// << "\" with value \"" << attr.value() << "\"" << endl;
Chris@66 221 attrs.append(attr.name(), "", "", attr.value());
Chris@66 222 }
Chris@66 223
Chris@66 224 setParameters(attrs);
Chris@66 225 }
Chris@163 226
Chris@66 227 QString
Chris@66 228 PluginXml::stripInvalidParameterNameCharacters(QString s) const
Chris@66 229 {
Chris@66 230 s.replace(QRegExp("[^a-zA-Z0-9_]*"), "");
Chris@66 231 return s;
Chris@66 232 }
Chris@66 233