# HG changeset patch # User Chris Cannam # Date 1221739772 0 # Node ID beb2948baa77d598d5b7ec40901f832d8cce817a # Parent 32c399d06374595b19ce82ae72b4214dd4302f82 * Merge revisions 1041 to 1130 from sv-rdf-import branch diff -r 32c399d06374 -r beb2948baa77 base/ProgressPrinter.cpp --- a/base/ProgressPrinter.cpp Thu Aug 07 16:06:59 2008 +0000 +++ b/base/ProgressPrinter.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -20,7 +20,8 @@ ProgressPrinter::ProgressPrinter(QString message, QObject *parent) : ProgressReporter(parent), m_prefix(message), - m_lastProgress(0) + m_lastProgress(0), + m_definite(true) { } @@ -32,6 +33,18 @@ // std::cerr << "(progress printer dtor)" << std::endl; } +bool +ProgressPrinter::isDefinite() const +{ + return m_definite; +} + +void +ProgressPrinter::setDefinite(bool definite) +{ + m_definite = definite; +} + void ProgressPrinter::setMessage(QString message) { @@ -46,8 +59,12 @@ else { std::cerr << "\r" << m_prefix.toStdString() - << (m_prefix == "" ? "" : " ") - << progress << "%"; + << (m_prefix == "" ? "" : " "); + if (m_definite) { + std::cerr << progress << "%"; + } else { + std::cerr << "|/-\\"[progress % 4]; + } } m_lastProgress = progress; } diff -r 32c399d06374 -r beb2948baa77 base/ProgressPrinter.h --- a/base/ProgressPrinter.h Thu Aug 07 16:06:59 2008 +0000 +++ b/base/ProgressPrinter.h Thu Sep 18 12:09:32 2008 +0000 @@ -26,6 +26,11 @@ ProgressPrinter(QString message, QObject *parent = 0); virtual ~ProgressPrinter(); + virtual bool isDefinite() const; + virtual void setDefinite(bool definite); + + virtual bool wasCancelled() const { return false; } // no mechanism + public slots: virtual void setMessage(QString); virtual void setProgress(int); @@ -33,6 +38,7 @@ protected: QString m_prefix; int m_lastProgress; + bool m_definite; }; #endif diff -r 32c399d06374 -r beb2948baa77 base/ProgressReporter.h --- a/base/ProgressReporter.h Thu Aug 07 16:06:59 2008 +0000 +++ b/base/ProgressReporter.h Thu Sep 18 12:09:32 2008 +0000 @@ -14,6 +14,7 @@ */ #ifndef _PROGRESS_REPORTER_H_ +#define _PROGRESS_REPORTER_H_ #include #include @@ -26,6 +27,11 @@ ProgressReporter(QObject *parent = 0); virtual ~ProgressReporter(); + virtual bool isDefinite() const = 0; + virtual void setDefinite(bool definite) = 0; // default should be definite + + virtual bool wasCancelled() const = 0; + signals: void cancelled(); diff -r 32c399d06374 -r beb2948baa77 base/RealTime.cpp --- a/base/RealTime.cpp Thu Aug 07 16:06:59 2008 +0000 +++ b/base/RealTime.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -79,6 +79,94 @@ return RealTime(tv.tv_sec, tv.tv_usec * 1000); } +RealTime +RealTime::fromXsdDuration(std::string xsdd) +{ + RealTime t; + + int year = 0, month = 0, day = 0, hour = 0, minute = 0; + double second = 0.0; + + int i = 0; + + const char *s = xsdd.c_str(); + int len = xsdd.length(); + + bool negative = false, afterT = false; + + int valstart = 0; + + while (i < len) { + + if (s[i] == '-') { + if (i == 0) negative = true; + ++i; + continue; + } + + double value = 0.0; + char *eptr = 0; + + if (isdigit(s[i]) || s[i] == '.') { + valstart = i; + value = strtod(&s[i], &eptr); + i = eptr - s; + } + + if (i == len) break; + + switch (s[i]) { + case 'Y': year = int(value + 0.1); break; + case 'D': day = int(value + 0.1); break; + case 'H': hour = int(value + 0.1); break; + case 'M': + if (afterT) minute = int(value + 0.1); + else month = int(value + 0.1); + break; + case 'S': + second = value; + break; + case 'T': afterT = true; break; + }; + + ++i; + } + + if (year > 0) { + std::cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero year.\nWith no origin and a limited data size, I will treat a year as exactly 31556952\nseconds and you should expect overflow and/or poor results." << std::endl; + t = t + RealTime(year * 31556952, 0); + } + + if (month > 0) { + std::cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero month.\nWith no origin and a limited data size, I will treat a month as exactly 2629746\nseconds and you should expect overflow and/or poor results." << std::endl; + t = t + RealTime(month * 2629746, 0); + } + + if (day > 0) { + t = t + RealTime(day * 86400, 0); + } + + if (hour > 0) { + t = t + RealTime(hour * 3600, 0); + } + + if (minute > 0) { + t = t + RealTime(minute * 60, 0); + } + + t = t + fromSeconds(second); + + return t; +} + +double +RealTime::toDouble() const +{ + double d = sec; + d += double(nsec) / double(ONE_BILLION); + return d; +} + std::ostream &operator<<(std::ostream &out, const RealTime &rt) { if (rt < RealTime::zeroTime) { @@ -128,7 +216,6 @@ RealTime::fromString(std::string s) { bool negative = false; - bool faulty = false; bool section = 0; std::string ssec, snsec; diff -r 32c399d06374 -r beb2948baa77 base/RealTime.h --- a/base/RealTime.h Thu Aug 07 16:06:59 2008 +0000 +++ b/base/RealTime.h Thu Sep 18 12:09:32 2008 +0000 @@ -49,6 +49,9 @@ static RealTime fromSeconds(double sec); static RealTime fromMilliseconds(int msec); static RealTime fromTimeval(const struct timeval &); + static RealTime fromXsdDuration(std::string xsdd); + + double toDouble() const; RealTime &operator=(const RealTime &r) { sec = r.sec; nsec = r.nsec; return *this; diff -r 32c399d06374 -r beb2948baa77 data/fileio/FileSource.cpp --- a/data/fileio/FileSource.cpp Thu Aug 07 16:06:59 2008 +0000 +++ b/data/fileio/FileSource.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -209,6 +209,8 @@ m_localFilename = m_url.toString(); literal = true; } + m_localFilename = QFileInfo(m_localFilename).absoluteFilePath(); + #ifdef DEBUG_FILE_SOURCE std::cerr << "FileSource::init: URL translates to local filename \"" << m_localFilename.toStdString() << "\"" << std::endl; diff -r 32c399d06374 -r beb2948baa77 data/model/EditableDenseThreeDimensionalModel.cpp --- a/data/model/EditableDenseThreeDimensionalModel.cpp Thu Aug 07 16:06:59 2008 +0000 +++ b/data/model/EditableDenseThreeDimensionalModel.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -178,6 +178,8 @@ bool allChange = false; + if (values.size() > m_yBinCount) m_yBinCount = values.size(); + for (size_t i = 0; i < values.size(); ++i) { float value = values[i]; if (std::isnan(value) || std::isinf(value)) { diff -r 32c399d06374 -r beb2948baa77 rdf/PluginRDFDescription.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/PluginRDFDescription.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,221 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "PluginRDFDescription.h" + +#include "PluginRDFIndexer.h" +#include "SimpleSPARQLQuery.h" + +#include "plugin/PluginIdentifier.h" + +#include +using std::cerr; +using std::endl; + +PluginRDFDescription::PluginRDFDescription(QString pluginId) : + m_pluginId(pluginId), + m_haveDescription(false) +{ + PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); + QString url = indexer->getDescriptionURLForPluginId(pluginId); + if (url == "") { + cerr << "PluginRDFDescription: WARNING: No RDF description available for plugin ID \"" + << pluginId.toStdString() << "\"" << endl; + } else { + if (!indexURL(url)) { + cerr << "PluginRDFDescription: ERROR: Failed to query RDF description for plugin ID \"" + << pluginId.toStdString() << "\"" << endl; + } else { + m_haveDescription = true; + } + } +} + +PluginRDFDescription::~PluginRDFDescription() +{ +} + +bool +PluginRDFDescription::haveDescription() const +{ + return m_haveDescription; +} + +PluginRDFDescription::OutputType +PluginRDFDescription::getOutputType(QString outputId) const +{ + if (m_outputTypes.find(outputId) == m_outputTypes.end()) { + return OutputTypeUnknown; + } + return m_outputTypes.find(outputId)->second; +} + +PluginRDFDescription::OutputDisposition +PluginRDFDescription::getOutputDisposition(QString outputId) const +{ + if (m_outputDispositions.find(outputId) == m_outputDispositions.end()) { + return OutputDispositionUnknown; + } + return m_outputDispositions.find(outputId)->second; +} + +QString +PluginRDFDescription::getOutputFeatureTypeURI(QString outputId) const +{ + if (m_outputFeatureTypeURIMap.find(outputId) == + m_outputFeatureTypeURIMap.end()) { + return ""; + } + return m_outputFeatureTypeURIMap.find(outputId)->second; +} + +QString +PluginRDFDescription::getOutputEventTypeURI(QString outputId) const +{ + if (m_outputEventTypeURIMap.find(outputId) == + m_outputEventTypeURIMap.end()) { + return ""; + } + return m_outputEventTypeURIMap.find(outputId)->second; +} + +QString +PluginRDFDescription::getOutputUnit(QString outputId) const +{ + if (m_outputUnitMap.find(outputId) == m_outputUnitMap.end()) { + return ""; + } + return m_outputUnitMap.find(outputId)->second; +} + +bool +PluginRDFDescription::indexURL(QString url) +{ + QString type, soname, label; + PluginIdentifier::parseIdentifier(m_pluginId, type, soname, label); + + SimpleSPARQLQuery query + (QString + ( + " PREFIX vamp: " + + " SELECT ?output_id ?output_type ?feature_type ?event_type ?unit " + " FROM <%1> " + + " WHERE { " + + " ?plugin a vamp:Plugin ; " + " vamp:identifier \"%2\" ; " + " vamp:output_descriptor ?output . " + + " ?output vamp:identifier ?output_id ; " + " a ?output_type . " + + " OPTIONAL { " + " ?output vamp:computes_feature_type ?feature_type " + " } . " + + " OPTIONAL { " + " ?output vamp:computes_event_type ?event_type " + " } . " + + " OPTIONAL { " + " ?output vamp:unit ?unit " + " } . " + + " } " + ) + .arg(url) + .arg(label)); + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + cerr << "ERROR: PluginRDFDescription::indexURL: ERROR: Failed to query document at <" + << url.toStdString() << ">: " + << query.getErrorString().toStdString() << endl; + return false; + } + + if (results.empty()) { + cerr << "ERROR: PluginRDFDescription::indexURL: NOTE: Document at <" + << url.toStdString() + << "> does not appear to describe any plugin outputs" << endl; + return false; + } + + // Note that an output may appear more than once, if it inherits + // more than one type (e.g. DenseOutput and QuantizedOutput). So + // these results must accumulate + + for (int i = 0; i < results.size(); ++i) { + + QString outputId = results[i]["output_id"].value; + + if (m_outputTypes.find(outputId) == m_outputTypes.end()) { + m_outputTypes[outputId] = OutputTypeUnknown; + } + + QString outputType = results[i]["output_type"].value; + + if (outputType.contains("DenseOutput")) { + m_outputDispositions[outputId] = OutputDense; + } else if (outputType.contains("SparseOutput")) { + m_outputDispositions[outputId] = OutputSparse; + } else if (outputType.contains("TrackLevelOutput")) { + m_outputDispositions[outputId] = OutputTrackLevel; + } + + if (results[i]["feature_type"].type == SimpleSPARQLQuery::URIValue) { + + QString featureType = results[i]["feature_type"].value; + + if (featureType != "") { + if (m_outputTypes[outputId] == OutputEvents) { + m_outputTypes[outputId] = OutputFeaturesAndEvents; + } else { + m_outputTypes[outputId] = OutputFeatures; + } + m_outputFeatureTypeURIMap[outputId] = featureType; + } + } + + if (results[i]["event_type"].type == SimpleSPARQLQuery::URIValue) { + + QString eventType = results[i]["event_type"].value; + + if (eventType != "") { + if (m_outputTypes[outputId] == OutputFeatures) { + m_outputTypes[outputId] = OutputFeaturesAndEvents; + } else { + m_outputTypes[outputId] = OutputEvents; + } + m_outputEventTypeURIMap[outputId] = eventType; + } + } + + if (results[i]["unit"].type == SimpleSPARQLQuery::LiteralValue) { + + QString unit = results[i]["unit"].value; + + if (unit != "") { + m_outputUnitMap[outputId] = unit; + } + } + } + + return true; +} + diff -r 32c399d06374 -r beb2948baa77 rdf/PluginRDFDescription.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/PluginRDFDescription.h Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,70 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _PLUGIN_RDF_DESCRIPTION_H_ +#define _PLUGIN_RDF_DESCRIPTION_H_ + +#include +#include + +class FileSource; + +class PluginRDFDescription +{ +public: + PluginRDFDescription() : m_haveDescription(false) { } + PluginRDFDescription(QString pluginId); + ~PluginRDFDescription(); + + enum OutputType + { + OutputTypeUnknown, + OutputFeatures, + OutputEvents, + OutputFeaturesAndEvents + }; + + enum OutputDisposition + { + OutputDispositionUnknown, + OutputSparse, + OutputDense, + OutputTrackLevel + }; + + bool haveDescription() const; + OutputType getOutputType(QString outputId) const; + OutputDisposition getOutputDisposition(QString outputId) const; + QString getOutputFeatureTypeURI(QString outputId) const; + QString getOutputEventTypeURI(QString outputId) const; + QString getOutputUnit(QString outputId) const; + +protected: + typedef std::map OutputTypeMap; + typedef std::map OutputDispositionMap; + typedef std::map OutputStringMap; + + QString m_pluginId; + bool m_haveDescription; + OutputTypeMap m_outputTypes; + OutputDispositionMap m_outputDispositions; + OutputStringMap m_outputFeatureTypeURIMap; + OutputStringMap m_outputEventTypeURIMap; + OutputStringMap m_outputUnitMap; + bool indexURL(QString url); +}; + +#endif + diff -r 32c399d06374 -r beb2948baa77 rdf/PluginRDFIndexer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/PluginRDFIndexer.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,286 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "PluginRDFIndexer.h" + +#include "SimpleSPARQLQuery.h" + +#include "data/fileio/FileSource.h" +#include "plugin/PluginIdentifier.h" + +#include + +#include +#include +#include + +#include +using std::cerr; +using std::endl; +using std::vector; +using std::string; +using Vamp::PluginHostAdapter; + +PluginRDFIndexer * +PluginRDFIndexer::m_instance = 0; + +PluginRDFIndexer * +PluginRDFIndexer::getInstance() +{ + if (!m_instance) m_instance = new PluginRDFIndexer(); + return m_instance; +} + +PluginRDFIndexer::PluginRDFIndexer() +{ + vector paths = PluginHostAdapter::getPluginPath(); + + QStringList filters; + filters << "*.n3"; + filters << "*.N3"; + filters << "*.rdf"; + filters << "*.RDF"; + + // Search each Vamp plugin path for a .rdf file that either has + // name "soname", "soname:label" or "soname/label" plus RDF + // extension. Use that order of preference, and prefer n3 over + // rdf extension. + + for (vector::const_iterator i = paths.begin(); i != paths.end(); ++i) { + + QDir dir(i->c_str()); + if (!dir.exists()) continue; + + QStringList entries = dir.entryList + (filters, QDir::Files | QDir::Readable); + + for (QStringList::const_iterator j = entries.begin(); + j != entries.end(); ++j) { + QFileInfo fi(dir.filePath(*j)); + indexFile(fi.absoluteFilePath()); + } + + QStringList subdirs = dir.entryList + (QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable); + + for (QStringList::const_iterator j = subdirs.begin(); + j != subdirs.end(); ++j) { + QDir subdir(dir.filePath(*j)); + if (subdir.exists()) { + entries = subdir.entryList + (filters, QDir::Files | QDir::Readable); + for (QStringList::const_iterator k = entries.begin(); + k != entries.end(); ++k) { + QFileInfo fi(subdir.filePath(*k)); + indexFile(fi.absoluteFilePath()); + } + } + } + } +} + +PluginRDFIndexer::~PluginRDFIndexer() +{ + while (!m_cache.empty()) { + delete *m_cache.begin(); + m_cache.erase(m_cache.begin()); + } +} + +QString +PluginRDFIndexer::getURIForPluginId(QString pluginId) +{ + if (m_idToUriMap.find(pluginId) == m_idToUriMap.end()) return ""; + return m_idToUriMap[pluginId]; +} + +QString +PluginRDFIndexer::getIdForPluginURI(QString uri) +{ + if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) { + + // Haven't found this uri referenced in any document on the + // local filesystem; try resolving the pre-fragment part of + // the uri as a document URL and reading that if possible. + + // Because we may want to refer to this document again, we + // cache it locally if it turns out to exist. + + cerr << "PluginRDFIndexer::getIdForPluginURI: NOTE: Failed to find a local RDF document describing plugin <" << uri.toStdString() << ">: attempting to retrieve one remotely by guesswork" << endl; + + QString baseUrl = QUrl(uri).toString(QUrl::RemoveFragment); + + FileSource source(baseUrl); + if (source.isAvailable()) { + source.waitForData(); + if (indexFile(source.getLocalFilename())) { + m_cache.insert(new FileSource(source)); + } + } + + if (m_uriToIdMap.find(uri) == m_uriToIdMap.end()) { + m_uriToIdMap[uri] = ""; + } + } + + return m_uriToIdMap[uri]; +} + +QString +PluginRDFIndexer::getDescriptionURLForPluginId(QString pluginId) +{ + if (m_idToDescriptionMap.find(pluginId) == m_idToDescriptionMap.end()) return ""; + return m_idToDescriptionMap[pluginId]; +} + +QString +PluginRDFIndexer::getDescriptionURLForPluginURI(QString uri) +{ + QString id = getIdForPluginURI(uri); + if (id == "") return ""; + return getDescriptionURLForPluginId(id); +} + +bool +PluginRDFIndexer::indexFile(QString filepath) +{ + QUrl url = QUrl::fromLocalFile(filepath); + QString urlString = url.toString(); + return indexURL(urlString); +} + +bool +PluginRDFIndexer::indexURL(QString urlString) +{ +// cerr << "PluginRDFIndexer::indexURL: url = <" << urlString.toStdString() << ">" << endl; + + SimpleSPARQLQuery query + (QString + ( + " PREFIX vamp: " + + " SELECT ?plugin ?library_id ?plugin_id " + " FROM <%1> " + + " WHERE { " + " ?plugin a vamp:Plugin . " + + // Make the identifier and library parts optional, so + // that we can check and report helpfully if one or both + // is absent instead of just getting no results + + " OPTIONAL { ?plugin vamp:identifier ?plugin_id } . " + + " OPTIONAL { " + " ?library a vamp:PluginLibrary ; " + " vamp:available_plugin ?plugin ; " + " vamp:identifier ?library_id " + " } " + " } " + ) + .arg(urlString)); + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + cerr << "ERROR: PluginRDFIndexer::indexURL: ERROR: Failed to index document at <" + << urlString.toStdString() << ">: " + << query.getErrorString().toStdString() << endl; + return false; + } + + if (results.empty()) { + cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" + << urlString.toStdString() + << "> does not describe any vamp:Plugin resources" << endl; + return false; + } + + bool foundSomething = false; + bool addedSomething = false; + + for (SimpleSPARQLQuery::ResultList::iterator i = results.begin(); + i != results.end(); ++i) { + + QString pluginUri = (*i)["plugin"].value; + QString soname = (*i)["library_id"].value; + QString identifier = (*i)["plugin_id"].value; + + if (identifier == "") { + cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" + << urlString.toStdString() + << "> fails to define any vamp:identifier for plugin <" + << pluginUri.toStdString() << ">" + << endl; + continue; + } + if (soname == "") { + cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" + << urlString.toStdString() << "> does not associate plugin <" + << pluginUri.toStdString() << "> with any implementation library" + << endl; + continue; + } +/* + cerr << "PluginRDFIndexer::indexURL: Document for plugin \"" + << soname.toStdString() << ":" << identifier.toStdString() + << "\" (uri <" << pluginUri.toStdString() << ">) is at url <" + << urlString.toStdString() << ">" << endl; +*/ + QString pluginId = PluginIdentifier::createIdentifier + ("vamp", soname, identifier); + + foundSomething = true; + + if (m_idToDescriptionMap.find(pluginId) != m_idToDescriptionMap.end()) { + cerr << "PluginRDFIndexer::indexURL: NOTE: Plugin id \"" + << pluginId.toStdString() << "\", described in document at <" + << urlString.toStdString() + << ">, has already been described in document <" + << m_idToDescriptionMap[pluginId].toStdString() + << ">: ignoring this new description" << endl; + continue; + } + + m_idToDescriptionMap[pluginId] = urlString; + m_idToUriMap[pluginId] = pluginUri; + + addedSomething = true; + + if (pluginUri != "") { + if (m_uriToIdMap.find(pluginUri) != m_uriToIdMap.end()) { + cerr << "PluginRDFIndexer::indexURL: WARNING: Found multiple plugins with the same URI:" << endl; + cerr << " 1. Plugin id \"" << m_uriToIdMap[pluginUri].toStdString() << "\"" << endl; + cerr << " described in <" << m_idToDescriptionMap[m_uriToIdMap[pluginUri]].toStdString() << ">" << endl; + cerr << " 2. Plugin id \"" << pluginId.toStdString() << "\"" << endl; + cerr << " described in <" << urlString.toStdString() << ">" << endl; + cerr << "both claim URI <" << pluginUri.toStdString() << ">" << endl; + } else { + m_uriToIdMap[pluginUri] = pluginId; + } + } + } + + if (!foundSomething) { + cerr << "PluginRDFIndexer::indexURL: NOTE: Document at <" + << urlString.toStdString() + << "> does not sufficiently describe any plugins" << endl; + } + + return addedSomething; +} + + + diff -r 32c399d06374 -r beb2948baa77 rdf/PluginRDFIndexer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/PluginRDFIndexer.h Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,50 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _PLUGIN_RDF_INDEXER_H_ +#define _PLUGIN_RDF_INDEXER_H_ + +#include +#include +#include + +class FileSource; + +class PluginRDFIndexer +{ +public: + static PluginRDFIndexer *getInstance(); + + QString getURIForPluginId(QString pluginId); + QString getIdForPluginURI(QString uri); + QString getDescriptionURLForPluginId(QString pluginId); + QString getDescriptionURLForPluginURI(QString uri); + + ~PluginRDFIndexer(); + +protected: + PluginRDFIndexer(); + typedef std::map StringMap; + StringMap m_uriToIdMap; + StringMap m_idToUriMap; + StringMap m_idToDescriptionMap; + bool indexFile(QString path); + bool indexURL(QString url); + std::set m_cache; + static PluginRDFIndexer *m_instance; +}; + +#endif + diff -r 32c399d06374 -r beb2948baa77 rdf/RDFImporter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/RDFImporter.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,435 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "RDFImporter.h" + +#include +#include + +#include +#include + +#include "SimpleSPARQLQuery.h" + +#include "base/ProgressReporter.h" +#include "base/RealTime.h" + +#include "data/model/SparseOneDimensionalModel.h" +#include "data/model/SparseTimeValueModel.h" +#include "data/model/EditableDenseThreeDimensionalModel.h" + +using std::cerr; +using std::endl; + +class RDFImporterImpl +{ +public: + RDFImporterImpl(QString url, int sampleRate); + virtual ~RDFImporterImpl(); + + bool isOK(); + QString getErrorString() const; + + std::vector getDataModels(ProgressReporter *); + +protected: + QString m_uristring; + QString m_errorString; + int m_sampleRate; + + typedef std::vector ValueList; + typedef std::map TimeValueMap; + typedef std::map TypeTimeValueMap; + typedef std::map SourceTypeTimeValueMap; + + void extractStructure(const TimeValueMap &map, bool &sparse, + int &minValueCount, int &maxValueCount); + + void fillModel(SparseOneDimensionalModel *, const TimeValueMap &); + void fillModel(SparseTimeValueModel *, const TimeValueMap &); + void fillModel(EditableDenseThreeDimensionalModel *, const TimeValueMap &); +}; + + +QString +RDFImporter::getKnownExtensions() +{ + return "*.rdf *.n3 *.ttl"; +} + +RDFImporter::RDFImporter(QString url, int sampleRate) : + m_d(new RDFImporterImpl(url, sampleRate)) +{ +} + +RDFImporter::~RDFImporter() +{ + delete m_d; +} + +bool +RDFImporter::isOK() +{ + return m_d->isOK(); +} + +QString +RDFImporter::getErrorString() const +{ + return m_d->getErrorString(); +} + +std::vector +RDFImporter::getDataModels(ProgressReporter *r) +{ + return m_d->getDataModels(r); +} + +RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) : + m_uristring(uri), + m_sampleRate(sampleRate) +{ +} + +RDFImporterImpl::~RDFImporterImpl() +{ +} + +bool +RDFImporterImpl::isOK() +{ + return (m_errorString == ""); +} + +QString +RDFImporterImpl::getErrorString() const +{ + return m_errorString; +} + +std::vector +RDFImporterImpl::getDataModels(ProgressReporter *reporter) +{ + std::vector models; + + // Our query is intended to retrieve every thing that has a time, + // and every feature type and value associated with a thing that + // has a time. + + // We will then need to refine this big bag of results into a set + // of data models. + + // Results that have different source signals should go into + // different models. + + // Results that have different feature types should go into + // different models. + + // Results that are sparse should go into different models from + // those that are dense (we need to examine the timestamps to + // establish this -- if the timestamps are regular, the results + // are dense -- so we can't do it as we go along, only after + // collecting all results). + + // Timed things that have features associated with them should not + // appear directly in any model -- their features should appear + // instead -- and these should be different models from those used + // for timed things that do not have features. + + // As we load the results, we'll push them into a partially + // structured container that maps from source signal (URI as + // string) -> feature type (likewise) -> time -> list of values. + // If the source signal or feature type is unavailable, the empty + // string will do. + + SourceTypeTimeValueMap m; + + QString queryString = QString( + + " PREFIX event: " + " PREFIX time: " + " PREFIX mo: " + " PREFIX af: " + + " SELECT ?signalSource ?time ?eventType ?value" + " FROM <%1>" + + " WHERE {" + " ?signal mo:available_as ?signalSource ." + " ?signal mo:time ?interval ." + " ?interval time:onTimeLine ?tl ." + " ?t time:onTimeLine ?tl ." + " ?t time:at ?time ." + " ?timedThing event:time ?t ." + " ?timedThing a ?eventType ." + " OPTIONAL {" + " ?timedThing af:hasFeature ?feature ." + " ?feature af:value ?value" + " }" + " }" + + ).arg(m_uristring); + + SimpleSPARQLQuery query(queryString); + query.setProgressReporter(reporter); + + cerr << "Query will be: " << queryString.toStdString() << endl; + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + m_errorString = query.getErrorString(); + return models; + } + + if (query.wasCancelled()) { + m_errorString = "Query cancelled"; + return models; + } + + for (int i = 0; i < results.size(); ++i) { + + QString source = results[i]["signalSource"].value; + + QString timestring = results[i]["time"].value; + RealTime time; + time = RealTime::fromXsdDuration(timestring.toStdString()); + cerr << "time = " << time.toString() << " (from xsd:duration \"" + << timestring.toStdString() << "\")" << endl; + + QString type = results[i]["eventType"].value; + + QString valuestring = results[i]["value"].value; + float value = 0.f; + bool haveValue = false; + if (valuestring != "") { + value = valuestring.toFloat(&haveValue); + cerr << "value = " << value << endl; + } + + if (haveValue) { + m[source][type][time].push_back(value); + } else if (m[source][type].find(time) == m[source][type].end()) { + m[source][type][time] = ValueList(); + } + } + + for (SourceTypeTimeValueMap::const_iterator mi = m.begin(); + mi != m.end(); ++mi) { + + QString source = mi->first; + + for (TypeTimeValueMap::const_iterator ttvi = mi->second.begin(); + ttvi != mi->second.end(); ++ttvi) { + + QString type = ttvi->first; + + // Now we need to work out what sort of model to use for + // this source/type combination. Ultimately we'll + // hopefully be able to map directly from the type to the + // model on the basis of known structures for the types, + // but we also want to be able to handle untyped data + // according to its apparent structure so let's do that + // first. + + bool sparse = false; + int minValueCount = 0, maxValueCount = 0; + + extractStructure(ttvi->second, sparse, minValueCount, maxValueCount); + + cerr << "For source \"" << source.toStdString() << "\", type \"" + << type.toStdString() << "\" we have sparse = " << sparse + << ", min value count = " << minValueCount << ", max = " + << maxValueCount << endl; + + // Model allocations: + // + // Sparse, no values: SparseOneDimensionalModel + // + // Sparse, always 1 value: SparseTimeValueModel + // + // Sparse, > 1 value: No standard model for this. If + // there are always 2 values, perhaps hack it into + // NoteModel for now? Or always use SparseTimeValueModel + // and discard all but the first value. + // + // Dense, no values: Meaningless; no suitable model + // + // Dense, > 0 values: EditableDenseThreeDimensionalModel + // + // These should just be our fallback positions; we want to + // be reading semantic data from the RDF in order to pick + // the right model directly + + enum { SODM, STVM, EDTDM } modelType = SODM; + + if (sparse) { + if (maxValueCount == 0) { + modelType = SODM; + } else if (minValueCount == 1 && maxValueCount == 1) { + modelType = STVM; + } else { + cerr << "WARNING: No suitable model available for sparse data with between " << minValueCount << " and " << maxValueCount << " values" << endl; + modelType = STVM; + } + } else { + if (maxValueCount == 0) { + cerr << "WARNING: Dense data set with no values is not meaningful, skipping" << endl; + continue; + } else { + modelType = EDTDM; + } + } + + //!!! set model name &c + + if (modelType == SODM) { + + SparseOneDimensionalModel *model = + new SparseOneDimensionalModel(m_sampleRate, 1, false); + + fillModel(model, ttvi->second); + models.push_back(model); + + } else if (modelType == STVM) { + + SparseTimeValueModel *model = + new SparseTimeValueModel(m_sampleRate, 1, false); + + fillModel(model, ttvi->second); + models.push_back(model); + + } else { + + EditableDenseThreeDimensionalModel *model = + new EditableDenseThreeDimensionalModel(m_sampleRate, 1, 0, + false); + + fillModel(model, ttvi->second); + models.push_back(model); + } + } + } + + + return models; +} + +void +RDFImporterImpl::extractStructure(const TimeValueMap &tvm, + bool &sparse, + int &minValueCount, + int &maxValueCount) +{ + // These are floats intentionally rather than RealTime -- + // see logic for handling rounding error below + float firstTime = 0.f; + float timeStep = 0.f; + bool haveTimeStep = false; + + for (TimeValueMap::const_iterator tvi = tvm.begin(); tvi != tvm.end(); ++tvi) { + + RealTime time = tvi->first; + int valueCount = tvi->second.size(); + + if (tvi == tvm.begin()) { + + minValueCount = valueCount; + maxValueCount = valueCount; + + firstTime = time.toDouble(); + + } else { + + if (valueCount < minValueCount) minValueCount = valueCount; + if (valueCount > maxValueCount) maxValueCount = valueCount; + + if (!haveTimeStep) { + timeStep = time.toDouble() - firstTime; + if (timeStep == 0.f) sparse = true; + haveTimeStep = true; + } else if (!sparse) { + // test whether this time is within + // rounding-error range of being an integer + // multiple of some constant away from the + // first time + float timeAsFloat = time.toDouble(); + int count = int((timeAsFloat - firstTime) / timeStep + 0.5); + float expected = firstTime + (timeStep * count); + if (fabsf(expected - timeAsFloat) > 1e-6) { + cerr << "Event at " << timeAsFloat << " is not evenly spaced -- would expect it to be " << expected << " for a spacing of " << count << " * " << timeStep << endl; + sparse = true; + } + } + } + } +} + +void +RDFImporterImpl::fillModel(SparseOneDimensionalModel *model, + const TimeValueMap &tvm) +{ + //!!! labels &c not yet handled + + for (TimeValueMap::const_iterator tvi = tvm.begin(); + tvi != tvm.end(); ++tvi) { + + RealTime time = tvi->first; + long frame = RealTime::realTime2Frame(time, m_sampleRate); + + SparseOneDimensionalModel::Point point(frame); + + model->addPoint(point); + } +} + +void +RDFImporterImpl::fillModel(SparseTimeValueModel *model, + const TimeValueMap &tvm) +{ + //!!! labels &c not yet handled + + for (TimeValueMap::const_iterator tvi = tvm.begin(); + tvi != tvm.end(); ++tvi) { + + RealTime time = tvi->first; + long frame = RealTime::realTime2Frame(time, m_sampleRate); + + float value = 0.f; + if (!tvi->second.empty()) value = *tvi->second.begin(); + + SparseTimeValueModel::Point point(frame, value, ""); + + model->addPoint(point); + } +} + +void +RDFImporterImpl::fillModel(EditableDenseThreeDimensionalModel *model, + const TimeValueMap &tvm) +{ + //!!! labels &c not yet handled + + //!!! start time offset not yet handled + + size_t col = 0; + + for (TimeValueMap::const_iterator tvi = tvm.begin(); + tvi != tvm.end(); ++tvi) { + + model->setColumn(col++, tvi->second); + } +} + diff -r 32c399d06374 -r beb2948baa77 rdf/RDFImporter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/RDFImporter.h Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,52 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RDF_IMPORTER_H_ +#define _RDF_IMPORTER_H_ + +#include +#include + +#include + +class Model; +class RDFImporterImpl; +class ProgressReporter; + +class RDFImporter : public QObject +{ + Q_OBJECT + +public: + /** + * Return the file extensions that we have data file readers for, + * in a format suitable for use with QFileDialog. For example, + * "*.rdf *.n3". + */ + static QString getKnownExtensions(); + + RDFImporter(QString url, int sampleRate); + virtual ~RDFImporter(); + + bool isOK(); + QString getErrorString() const; + + std::vector getDataModels(ProgressReporter *reporter); + +protected: + RDFImporterImpl *m_d; +}; + +#endif diff -r 32c399d06374 -r beb2948baa77 rdf/RDFTransformFactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/RDFTransformFactory.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,258 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "RDFTransformFactory.h" + +#include +#include + +#include +#include + +#include +#include + +#include "SimpleSPARQLQuery.h" +#include "PluginRDFIndexer.h" +#include "base/ProgressReporter.h" + +#include "transform/TransformFactory.h" + +using std::cerr; +using std::endl; + +typedef const unsigned char *STR; // redland's expected string type + + +class RDFTransformFactoryImpl +{ +public: + RDFTransformFactoryImpl(QString url); + virtual ~RDFTransformFactoryImpl(); + + bool isOK(); + QString getErrorString() const; + + std::vector getTransforms(ProgressReporter *); + +protected: + QString m_urlString; + QString m_errorString; +}; + + +QString +RDFTransformFactory::getKnownExtensions() +{ + return "*.rdf *.n3 *.ttl"; +} + +RDFTransformFactory::RDFTransformFactory(QString url) : + m_d(new RDFTransformFactoryImpl(url)) +{ +} + +RDFTransformFactory::~RDFTransformFactory() +{ + delete m_d; +} + +bool +RDFTransformFactory::isOK() +{ + return m_d->isOK(); +} + +QString +RDFTransformFactory::getErrorString() const +{ + return m_d->getErrorString(); +} + +std::vector +RDFTransformFactory::getTransforms(ProgressReporter *r) +{ + return m_d->getTransforms(r); +} + +RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) : + m_urlString(url) +{ +} + +RDFTransformFactoryImpl::~RDFTransformFactoryImpl() +{ +} + +bool +RDFTransformFactoryImpl::isOK() +{ + return (m_errorString == ""); +} + +QString +RDFTransformFactoryImpl::getErrorString() const +{ + return m_errorString; +} + +std::vector +RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter) +{ + std::vector transforms; + + SimpleSPARQLQuery query + (QString + ( + " PREFIX vamp: " + + " SELECT ?transform ?plugin ?output ?program " + " ?step_size ?block_size ?window_type " + " ?sample_rate ?start ?duration " + + " FROM <%1> " + + " WHERE { " + " ?transform a vamp:Transform ; " + " vamp:plugin ?plugin . " + " OPTIONAL { ?transform vamp:output ?output } . " + " OPTIONAL { ?transform vamp:program ?program } . " + " OPTIONAL { ?transform vamp:step_size ?step_size } . " + " OPTIONAL { ?transform vamp:block_size ?block_size } . " + " OPTIONAL { ?transform vamp:window_type ?window_type } . " + " OPTIONAL { ?transform vamp:sample_rate ?sample_rate } . " + " OPTIONAL { ?transform vamp:start ?start } . " + " OPTIONAL { ?transform vamp:duration ?duration } " + " } " + ) + .arg(m_urlString)); + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + m_errorString = query.getErrorString(); + return transforms; + } + + if (query.wasCancelled()) { + m_errorString = "Query cancelled"; + return transforms; + } + + PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); + + for (int i = 0; i < results.size(); ++i) { + + SimpleSPARQLQuery::KeyValueMap &result = results[i]; + + QString transformUri = result["transform"].value; + QString pluginUri = result["plugin"].value; + + QString pluginId = indexer->getIdForPluginURI(pluginUri); + + if (pluginId == "") { + cerr << "RDFTransformFactory: WARNING: Unknown plugin <" + << pluginUri.toStdString() << "> for transform <" + << transformUri.toStdString() << ">" << endl; + continue; + } + + Transform transform; + transform.setPluginIdentifier(pluginId); + + if (result["output"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setOutput(result["output"].value); + } + + if (result["program"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setProgram(result["program"].value); + } + + if (result["step_size"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setStepSize(result["step_size"].value.toUInt()); + } + + if (result["block_size"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setBlockSize(result["block_size"].value.toUInt()); + } + + if (result["window_type"].type == SimpleSPARQLQuery::LiteralValue) { + cerr << "NOTE: can't handle window type yet (value is \"" + << result["window_type"].value.toStdString() << "\")" << endl; + } + + if (result["sample_rate"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setStepSize(result["sample_rate"].value.toFloat()); + } + + if (result["start"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setStartTime(RealTime::fromXsdDuration + (result["start"].value.toStdString())); + } + + if (result["duration"].type == SimpleSPARQLQuery::LiteralValue) { + transform.setDuration(RealTime::fromXsdDuration + (result["duration"].value.toStdString())); + } + + SimpleSPARQLQuery paramQuery + (QString + ( + " PREFIX vamp: " + + " SELECT ?param_id ?param_value " + + " FROM <%1> " + + " WHERE { " + " <%2> vamp:parameter ?param . " + " ?param vamp:identifier ?param_id ; " + " vamp:value ?param_value " + " } " + ) + .arg(m_urlString) + .arg(transformUri)); + + SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute(); + + if (!paramQuery.isOK()) { + m_errorString = paramQuery.getErrorString(); + return transforms; + } + + if (paramQuery.wasCancelled()) { + m_errorString = "Query cancelled"; + return transforms; + } + + for (int j = 0; j < paramResults.size(); ++j) { + + QString paramId = paramResults[j]["param_id"].value; + QString paramValue = paramResults[j]["param_value"].value; + + if (paramId == "" || paramValue == "") continue; + + transform.setParameter(paramId, paramValue.toFloat()); + } + + cerr << "RDFTransformFactory: NOTE: Transform is: " << endl; + cerr << transform.toXmlString().toStdString() << endl; + + transforms.push_back(transform); + } + + return transforms; +} + diff -r 32c399d06374 -r beb2948baa77 rdf/RDFTransformFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/RDFTransformFactory.h Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,48 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RDF_TRANSFORM_FACTORY_H_ +#define _RDF_TRANSFORM_FACTORY_H_ + +#include +#include + +#include + +#include "transform/Transform.h" + +class RDFTransformFactoryImpl; +class ProgressReporter; + +class RDFTransformFactory : public QObject +{ + Q_OBJECT + +public: + static QString getKnownExtensions(); + + RDFTransformFactory(QString url); + virtual ~RDFTransformFactory(); + + bool isOK(); + QString getErrorString() const; + + std::vector getTransforms(ProgressReporter *reporter); + +protected: + RDFTransformFactoryImpl *m_d; +}; + +#endif diff -r 32c399d06374 -r beb2948baa77 rdf/SimpleSPARQLQuery.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/SimpleSPARQLQuery.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,235 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "SimpleSPARQLQuery.h" +#include "base/ProgressReporter.h" + +#include + +#include + +using std::cerr; +using std::endl; + +class SimpleSPARQLQuery::Impl +{ +public: + Impl(QString query); + ~Impl(); + + void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; } + bool wasCancelled() const { return m_cancelled; } + + ResultList execute(); + + bool isOK() const; + QString getErrorString() const; + +protected: + static void errorHandler(void *, raptor_locator *, const char *); + + static bool m_initialised; + + QString m_query; + QString m_errorString; + ProgressReporter *m_reporter; + bool m_cancelled; +}; + +SimpleSPARQLQuery::SimpleSPARQLQuery(QString query) : + m_impl(new Impl(query)) { } + +SimpleSPARQLQuery::~SimpleSPARQLQuery() +{ + delete m_impl; +} + +void +SimpleSPARQLQuery::setProgressReporter(ProgressReporter *reporter) +{ + m_impl->setProgressReporter(reporter); +} + +bool +SimpleSPARQLQuery::wasCancelled() const +{ + return m_impl->wasCancelled(); +} + +SimpleSPARQLQuery::ResultList +SimpleSPARQLQuery::execute() +{ + return m_impl->execute(); +} + +bool +SimpleSPARQLQuery::isOK() const +{ + return m_impl->isOK(); +} + +QString +SimpleSPARQLQuery::getErrorString() const +{ + return m_impl->getErrorString(); +} + +bool +SimpleSPARQLQuery::Impl::m_initialised = false; + +SimpleSPARQLQuery::Impl::Impl(QString query) : + m_query(query), + m_reporter(0), + m_cancelled(false) +{ + //!!! fortunately this global stuff goes away in future rasqal versions + if (!m_initialised) { + rasqal_init(); + } +} + +SimpleSPARQLQuery::Impl::~Impl() +{ +//!!! rasqal_finish(); +} + +bool +SimpleSPARQLQuery::Impl::isOK() const +{ + return (m_errorString == ""); +} + +QString +SimpleSPARQLQuery::Impl::getErrorString() const +{ + return m_errorString; +} + +void +SimpleSPARQLQuery::Impl::errorHandler(void *data, + raptor_locator *locator, + const char *message) +{ + SimpleSPARQLQuery::Impl *impl = (SimpleSPARQLQuery::Impl *)data; + +// char buffer[256]; +// raptor_format_locator(buffer, 255, locator); +// impl->m_errorString = QString("%1 - %2").arg(buffer).arg(message); + + impl->m_errorString = message; + + cerr << "SimpleSPARQLQuery: ERROR: " << impl->m_errorString.toStdString() << endl; +} + +SimpleSPARQLQuery::ResultList +SimpleSPARQLQuery::Impl::execute() +{ + ResultList list; + + rasqal_query *query = rasqal_new_query("sparql", NULL); + if (!query) { + m_errorString = "Failed to construct query"; + cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl; + return list; + } + + rasqal_query_set_error_handler(query, this, errorHandler); + rasqal_query_set_fatal_error_handler(query, this, errorHandler); + + if (rasqal_query_prepare + (query, (const unsigned char *)m_query.toUtf8().data(), NULL)) { + cerr << "SimpleSPARQLQuery: Failed to prepare query" << endl; + rasqal_free_query(query); + return list; + } + + rasqal_query_results *results = rasqal_query_execute(query); + +// cerr << "Query executed" << endl; + + if (!results) { + cerr << "SimpleSPARQLQuery: RASQAL query failed" << endl; + rasqal_free_query(query); + return list; + } + + if (!rasqal_query_results_is_bindings(results)) { + cerr << "SimpleSPARQLQuery: RASQAL query has wrong result type (not bindings)" << endl; + rasqal_free_query_results(results); + rasqal_free_query(query); + return list; + } + + int resultCount = 0; + int resultTotal = rasqal_query_results_get_count(results); // probably wrong + m_cancelled = false; + + while (!rasqal_query_results_finished(results)) { + + int count = rasqal_query_results_get_bindings_count(results); + + KeyValueMap resultmap; + + for (int i = 0; i < count; ++i) { + + const unsigned char *name = + rasqal_query_results_get_binding_name(results, i); + + rasqal_literal *literal = + rasqal_query_results_get_binding_value(results, i); + + QString key = (const char *)name; + + if (!literal) { + resultmap[key] = Value(); + continue; + } + + ValueType type = LiteralValue; + if (literal->type == RASQAL_LITERAL_URI) type = URIValue; + else if (literal->type == RASQAL_LITERAL_BLANK) type = BlankValue; + + QString text = (const char *)rasqal_literal_as_string(literal); + + resultmap[key] = Value(type, text); + } + + list.push_back(resultmap); + + rasqal_query_results_next(results); + + resultCount++; + + if (m_reporter) { + if (resultCount >= resultTotal) { + if (m_reporter->isDefinite()) m_reporter->setDefinite(false); + m_reporter->setProgress(resultCount); + } else { + m_reporter->setProgress((resultCount * 100) / resultTotal); + } + + if (m_reporter->wasCancelled()) { + m_cancelled = true; + break; + } + } + } + + rasqal_free_query_results(results); + rasqal_free_query(query); + + return list; +} + diff -r 32c399d06374 -r beb2948baa77 rdf/SimpleSPARQLQuery.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/SimpleSPARQLQuery.h Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,56 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _SIMPLE_SPARQL_QUERY_H_ +#define _SIMPLE_SPARQL_QUERY_H_ + +#include +#include +#include + +class ProgressReporter; + +class SimpleSPARQLQuery +{ +public: + enum ValueType { NoValue, URIValue, LiteralValue, BlankValue }; + + struct Value { + Value() : type(NoValue), value() { } + Value(ValueType t, QString v) : type(t), value(v) { } + ValueType type; + QString value; + }; + + typedef std::map KeyValueMap; + typedef std::vector ResultList; + + SimpleSPARQLQuery(QString query); + ~SimpleSPARQLQuery(); + + void setProgressReporter(ProgressReporter *reporter); + bool wasCancelled() const; + + ResultList execute(); + + bool isOK() const; + QString getErrorString() const; + +protected: + class Impl; + Impl *m_impl; +}; + +#endif diff -r 32c399d06374 -r beb2948baa77 rdf/rdf.pro --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rdf/rdf.pro Thu Sep 18 12:09:32 2008 +0000 @@ -0,0 +1,26 @@ +TEMPLATE = lib + +SV_UNIT_PACKAGES = redland +load(../sv.prf) + +CONFIG += sv staticlib qt thread warn_on stl rtti exceptions + +TARGET = svrdf + +DEPENDPATH += . .. +INCLUDEPATH += . .. +OBJECTS_DIR = tmp_obj +MOC_DIR = tmp_moc + +# Input +HEADERS += PluginRDFDescription.h \ + PluginRDFIndexer.h \ + RDFImporter.h \ + RDFTransformFactory.h \ + SimpleSPARQLQuery.h +SOURCES += PluginRDFDescription.cpp \ + PluginRDFIndexer.cpp \ + RDFImporter.cpp \ + RDFTransformFactory.cpp \ + SimpleSPARQLQuery.cpp + diff -r 32c399d06374 -r beb2948baa77 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Thu Aug 07 16:06:59 2008 +0000 +++ b/transform/TransformFactory.cpp Thu Sep 18 12:09:32 2008 +0000 @@ -484,14 +484,18 @@ FeatureExtractionPluginFactory *factory = FeatureExtractionPluginFactory::instanceFor(pluginId); - plugin = factory->instantiatePlugin(pluginId, rate); + if (factory) { + plugin = factory->instantiatePlugin(pluginId, rate); + } } else { RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(pluginId); - - plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1); + + if (factory) { + plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1); + } } return plugin;