Chris@439: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@439: Chris@439: /* Chris@439: Sonic Visualiser Chris@439: An audio file viewer and annotation editor. Chris@439: Centre for Digital Music, Queen Mary, University of London. Chris@439: This file copyright 2008 QMUL. Chris@439: Chris@439: This program is free software; you can redistribute it and/or Chris@439: modify it under the terms of the GNU General Public License as Chris@439: published by the Free Software Foundation; either version 2 of the Chris@439: License, or (at your option) any later version. See the file Chris@439: COPYING included with this distribution for more information. Chris@439: */ Chris@439: Chris@439: #include "PluginRDFDescription.h" Chris@439: Chris@439: #include "PluginRDFIndexer.h" Chris@439: #include "SimpleSPARQLQuery.h" Chris@439: Chris@457: #include "data/fileio/FileSource.h" Chris@468: #include "data/fileio/CachedFile.h" Chris@457: Chris@457: #include "base/Profiler.h" Chris@457: Chris@439: #include "plugin/PluginIdentifier.h" Chris@439: Chris@439: #include Chris@439: using std::cerr; Chris@439: using std::endl; Chris@439: Chris@439: PluginRDFDescription::PluginRDFDescription(QString pluginId) : Chris@439: m_pluginId(pluginId), Chris@439: m_haveDescription(false) Chris@439: { Chris@439: PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); Chris@439: QString url = indexer->getDescriptionURLForPluginId(pluginId); Chris@439: if (url == "") { Chris@439: cerr << "PluginRDFDescription: WARNING: No RDF description available for plugin ID \"" Chris@439: << pluginId.toStdString() << "\"" << endl; Chris@439: } else { Chris@439: if (!indexURL(url)) { Chris@439: cerr << "PluginRDFDescription: ERROR: Failed to query RDF description for plugin ID \"" Chris@439: << pluginId.toStdString() << "\"" << endl; Chris@439: } else { Chris@439: m_haveDescription = true; Chris@439: } Chris@439: } Chris@439: } Chris@439: Chris@439: PluginRDFDescription::~PluginRDFDescription() Chris@439: { Chris@439: } Chris@439: Chris@439: bool Chris@439: PluginRDFDescription::haveDescription() const Chris@439: { Chris@439: return m_haveDescription; Chris@439: } Chris@439: Chris@457: QString Chris@457: PluginRDFDescription::getPluginName() const Chris@457: { Chris@457: return m_pluginName; Chris@457: } Chris@457: Chris@457: QString Chris@457: PluginRDFDescription::getPluginDescription() const Chris@457: { Chris@457: return m_pluginDescription; Chris@457: } Chris@457: Chris@457: QString Chris@457: PluginRDFDescription::getPluginMaker() const Chris@457: { Chris@457: return m_pluginMaker; Chris@457: } Chris@457: Chris@462: QString Chris@462: PluginRDFDescription::getPluginInfoURL() const Chris@462: { Chris@462: return m_pluginInfoURL; Chris@462: } Chris@462: Chris@457: QStringList Chris@457: PluginRDFDescription::getOutputIds() const Chris@457: { Chris@457: QStringList ids; Chris@457: for (OutputDispositionMap::const_iterator i = m_outputDispositions.begin(); Chris@457: i != m_outputDispositions.end(); ++i) { Chris@457: ids.push_back(i->first); Chris@457: } Chris@457: return ids; Chris@457: } Chris@457: Chris@457: QString Chris@457: PluginRDFDescription::getOutputName(QString outputId) const Chris@457: { Chris@457: if (m_outputNames.find(outputId) == m_outputNames.end()) { Chris@457: return ""; Chris@457: } Chris@457: return m_outputNames.find(outputId)->second; Chris@457: } Chris@457: Chris@439: PluginRDFDescription::OutputDisposition Chris@439: PluginRDFDescription::getOutputDisposition(QString outputId) const Chris@439: { Chris@439: if (m_outputDispositions.find(outputId) == m_outputDispositions.end()) { Chris@439: return OutputDispositionUnknown; Chris@439: } Chris@439: return m_outputDispositions.find(outputId)->second; Chris@439: } Chris@439: Chris@439: QString Chris@439: PluginRDFDescription::getOutputEventTypeURI(QString outputId) const Chris@439: { Chris@439: if (m_outputEventTypeURIMap.find(outputId) == Chris@439: m_outputEventTypeURIMap.end()) { Chris@439: return ""; Chris@439: } Chris@439: return m_outputEventTypeURIMap.find(outputId)->second; Chris@439: } Chris@439: Chris@439: QString Chris@440: PluginRDFDescription::getOutputFeatureAttributeURI(QString outputId) const Chris@440: { Chris@440: if (m_outputFeatureAttributeURIMap.find(outputId) == Chris@440: m_outputFeatureAttributeURIMap.end()) { Chris@440: return ""; Chris@440: } Chris@440: return m_outputFeatureAttributeURIMap.find(outputId)->second; Chris@440: } Chris@440: Chris@440: QString Chris@440: PluginRDFDescription::getOutputSignalTypeURI(QString outputId) const Chris@440: { Chris@440: if (m_outputSignalTypeURIMap.find(outputId) == Chris@440: m_outputSignalTypeURIMap.end()) { Chris@440: return ""; Chris@440: } Chris@440: return m_outputSignalTypeURIMap.find(outputId)->second; Chris@440: } Chris@440: Chris@440: QString Chris@439: PluginRDFDescription::getOutputUnit(QString outputId) const Chris@439: { Chris@439: if (m_outputUnitMap.find(outputId) == m_outputUnitMap.end()) { Chris@439: return ""; Chris@439: } Chris@439: return m_outputUnitMap.find(outputId)->second; Chris@439: } Chris@439: Chris@439: bool Chris@439: PluginRDFDescription::indexURL(QString url) Chris@439: { Chris@457: Profiler profiler("PluginRDFDescription::indexURL"); Chris@457: Chris@439: QString type, soname, label; Chris@439: PluginIdentifier::parseIdentifier(m_pluginId, type, soname, label); Chris@439: Chris@457: bool success = true; Chris@457: Chris@457: QString local = url; Chris@457: Chris@457: if (FileSource::isRemote(url) && Chris@457: FileSource::canHandleScheme(url)) { Chris@461: Chris@468: CachedFile cf(url); Chris@468: if (!cf.isOK()) { Chris@468: return false; Chris@468: } Chris@468: Chris@468: local = QUrl::fromLocalFile(cf.getLocalFilename()).toString(); Chris@457: } Chris@457: Chris@457: if (!indexMetadata(local, label)) success = false; Chris@457: if (!indexOutputs(local, label)) success = false; Chris@457: Chris@457: return success; Chris@457: } Chris@457: Chris@457: bool Chris@457: PluginRDFDescription::indexMetadata(QString url, QString label) Chris@457: { Chris@457: Profiler profiler("PluginRDFDescription::indexMetadata"); Chris@457: Chris@457: QString queryTemplate = Chris@457: QString( Chris@457: " PREFIX vamp: " Chris@457: " PREFIX foaf: " Chris@457: " PREFIX dc: " Chris@457: " SELECT ?%4 FROM <%1> " Chris@457: " WHERE { " Chris@457: " ?plugin a vamp:Plugin ; " Chris@457: " vamp:identifier \"%2\" ; " Chris@457: " %3 ?%4 . " Chris@457: " }") Chris@457: .arg(url) Chris@457: .arg(label); Chris@457: Chris@457: SimpleSPARQLQuery::Value v; Chris@457: Chris@457: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, queryTemplate.arg("vamp:name").arg("name"), "name"); Chris@457: Chris@457: if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") { Chris@457: m_pluginName = v.value; Chris@457: } Chris@457: Chris@457: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, queryTemplate.arg("dc:description").arg("description"), "description"); Chris@457: Chris@457: if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") { Chris@457: m_pluginDescription = v.value; Chris@457: } Chris@457: Chris@457: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, Chris@480: QString( Chris@457: " PREFIX vamp: " Chris@457: " PREFIX foaf: " Chris@457: " SELECT ?name FROM <%1> " Chris@457: " WHERE { " Chris@457: " ?plugin a vamp:Plugin ; " Chris@457: " vamp:identifier \"%2\" ; " Chris@457: " foaf:maker ?maker . " Chris@457: " ?maker foaf:name ?name . " Chris@457: " }") Chris@457: .arg(url) Chris@457: .arg(label), "name"); Chris@457: Chris@457: if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") { Chris@457: m_pluginMaker = v.value; Chris@457: } Chris@457: Chris@462: // If we have a more-information URL for this plugin, then we take Chris@463: // that. Otherwise, a more-information URL for the plugin Chris@462: // library would do nicely. Failing that, we could perhaps use Chris@462: // any foaf:page URL at all that appears in the file -- but Chris@462: // perhaps that would be unwise Chris@462: Chris@462: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, Chris@480: QString( Chris@462: " PREFIX vamp: " Chris@462: " PREFIX foaf: " Chris@462: " SELECT ?page from <%1> " Chris@462: " WHERE { " Chris@462: " ?plugin a vamp:Plugin ; " Chris@462: " vamp:identifier \"%2\" ; " Chris@462: " foaf:page ?page . " Chris@462: " }") Chris@462: .arg(url) Chris@462: .arg(label), "page"); Chris@462: Chris@462: if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { Chris@462: Chris@462: m_pluginInfoURL = v.value; Chris@462: Chris@462: } else { Chris@462: Chris@462: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, Chris@480: QString( Chris@462: " PREFIX vamp: " Chris@462: " PREFIX foaf: " Chris@462: " SELECT ?page from <%1> " Chris@462: " WHERE { " Chris@462: " ?library a vamp:PluginLibrary ; " Chris@462: " vamp:available_plugin ?plugin ; " Chris@462: " foaf:page ?page . " Chris@462: " ?plugin a vamp:Plugin ; " Chris@462: " vamp:identifier \"%2\" . " Chris@462: " }") Chris@462: .arg(url) Chris@462: .arg(label), "page"); Chris@462: Chris@462: if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { Chris@462: Chris@462: m_pluginInfoURL = v.value; Chris@462: } Chris@462: } Chris@462: Chris@457: return true; Chris@457: } Chris@457: Chris@457: bool Chris@457: PluginRDFDescription::indexOutputs(QString url, QString label) Chris@457: { Chris@457: Profiler profiler("PluginRDFDescription::indexOutputs"); Chris@457: Chris@439: SimpleSPARQLQuery query Chris@480: (url, Chris@480: QString Chris@439: ( Chris@439: " PREFIX vamp: " Chris@439: Chris@440: " SELECT ?output ?output_id ?output_type ?unit " Chris@439: " FROM <%1> " Chris@439: Chris@439: " WHERE { " Chris@439: Chris@439: " ?plugin a vamp:Plugin ; " Chris@439: " vamp:identifier \"%2\" ; " Chris@440: " vamp:output ?output . " Chris@439: Chris@439: " ?output vamp:identifier ?output_id ; " Chris@439: " a ?output_type . " Chris@439: Chris@439: " OPTIONAL { " Chris@439: " ?output vamp:unit ?unit " Chris@439: " } . " Chris@439: Chris@439: " } " Chris@439: ) Chris@439: .arg(url) Chris@439: .arg(label)); Chris@439: Chris@439: SimpleSPARQLQuery::ResultList results = query.execute(); Chris@439: Chris@439: if (!query.isOK()) { Chris@439: cerr << "ERROR: PluginRDFDescription::indexURL: ERROR: Failed to query document at <" Chris@439: << url.toStdString() << ">: " Chris@439: << query.getErrorString().toStdString() << endl; Chris@439: return false; Chris@439: } Chris@439: Chris@439: if (results.empty()) { Chris@439: cerr << "ERROR: PluginRDFDescription::indexURL: NOTE: Document at <" Chris@439: << url.toStdString() Chris@440: << "> does not appear to describe any outputs for plugin with id \"" Chris@440: << label.toStdString() << "\"" << endl; Chris@439: return false; Chris@439: } Chris@439: Chris@439: // Note that an output may appear more than once, if it inherits Chris@439: // more than one type (e.g. DenseOutput and QuantizedOutput). So Chris@439: // these results must accumulate Chris@439: Chris@439: for (int i = 0; i < results.size(); ++i) { Chris@439: Chris@440: QString outputUri = results[i]["output"].value; Chris@439: QString outputId = results[i]["output_id"].value; Chris@439: QString outputType = results[i]["output_type"].value; Chris@439: Chris@439: if (outputType.contains("DenseOutput")) { Chris@439: m_outputDispositions[outputId] = OutputDense; Chris@439: } else if (outputType.contains("SparseOutput")) { Chris@439: m_outputDispositions[outputId] = OutputSparse; Chris@439: } else if (outputType.contains("TrackLevelOutput")) { Chris@439: m_outputDispositions[outputId] = OutputTrackLevel; Chris@457: } else { Chris@457: m_outputDispositions[outputId] = OutputDispositionUnknown; Chris@439: } Chris@439: Chris@439: if (results[i]["unit"].type == SimpleSPARQLQuery::LiteralValue) { Chris@439: Chris@439: QString unit = results[i]["unit"].value; Chris@439: Chris@439: if (unit != "") { Chris@439: m_outputUnitMap[outputId] = unit; Chris@439: } Chris@439: } Chris@440: Chris@457: SimpleSPARQLQuery::Value v; Chris@457: Chris@457: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, Chris@480: QString(" PREFIX vamp: " Chris@457: " PREFIX dc: " Chris@457: " SELECT ?title FROM <%1> " Chris@457: " WHERE { <%2> dc:title ?title } ") Chris@457: .arg(url).arg(outputUri), "title"); Chris@457: Chris@457: if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") { Chris@457: m_outputNames[outputId] = v.value; Chris@457: } Chris@457: Chris@440: QString queryTemplate = Chris@440: QString(" PREFIX vamp: " Chris@440: " SELECT ?%3 FROM <%1> " Chris@440: " WHERE { <%2> vamp:computes_%3 ?%3 } ") Chris@440: .arg(url).arg(outputUri); Chris@440: Chris@440: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, queryTemplate.arg("event_type"), "event_type"); Chris@440: Chris@440: if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { Chris@440: m_outputEventTypeURIMap[outputId] = v.value; Chris@440: } Chris@440: Chris@440: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, queryTemplate.arg("feature_attribute"), "feature_attribute"); Chris@440: Chris@440: if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { Chris@440: m_outputFeatureAttributeURIMap[outputId] = v.value; Chris@440: } Chris@440: Chris@440: v = SimpleSPARQLQuery::singleResultQuery Chris@480: (url, queryTemplate.arg("signal_type"), "signal_type"); Chris@440: Chris@440: if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { Chris@440: m_outputSignalTypeURIMap[outputId] = v.value; Chris@440: } Chris@439: } Chris@439: Chris@439: return true; Chris@439: } Chris@439: