Mercurial > hg > svcore
changeset 440:5746c559af15
* Merge revisions 1131 to 1201 from sv-rdf-import branch
author | Chris Cannam |
---|---|
date | Thu, 18 Sep 2008 12:33:30 +0000 |
parents | beb2948baa77 |
children | 288f45533041 |
files | data/fileio/AudioFileReaderFactory.cpp data/fileio/PlaylistFileReader.cpp data/fileio/PlaylistFileReader.h rdf/PluginRDFDescription.cpp rdf/PluginRDFDescription.h rdf/PluginRDFIndexer.cpp rdf/RDFImporter.cpp rdf/RDFTransformFactory.cpp rdf/SimpleSPARQLQuery.cpp rdf/SimpleSPARQLQuery.h rdf/rdf.pro |
diffstat | 11 files changed, 723 insertions(+), 199 deletions(-) [+] |
line wrap: on
line diff
--- a/data/fileio/AudioFileReaderFactory.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/data/fileio/AudioFileReaderFactory.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -104,6 +104,10 @@ ResamplingWavFileReader::CacheInTemporaryFile, targetRate, reporter); + if (!reader->isOK()) { + delete reader; + reader = 0; + } } } @@ -119,6 +123,10 @@ OggVorbisFileReader::CacheInTemporaryFile, targetRate, reporter); + if (!reader->isOK()) { + delete reader; + reader = 0; + } } } #endif @@ -135,6 +143,10 @@ MP3FileReader::CacheInTemporaryFile, targetRate, reporter); + if (!reader->isOK()) { + delete reader; + reader = 0; + } } } #endif @@ -150,6 +162,99 @@ QuickTimeFileReader::CacheInTemporaryFile, targetRate, reporter); + if (!reader->isOK()) { + delete reader; + reader = 0; + } + } + } +#endif + + // If none of the readers claimed to support this file extension, + // perhaps the extension is missing or misleading. Try again, + // ignoring it. We have to be confident that the reader won't + // open just any old text file or whatever and pretend it's + // succeeded + + if (!reader) { + + reader = new WavFileReader(source); + + if (targetRate != 0 && + reader->isOK() && + reader->getSampleRate() != targetRate) { + + std::cerr << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", creating resampling reader" << std::endl; + + delete reader; + reader = new ResamplingWavFileReader + (source, + threading ? + ResamplingWavFileReader::ResampleThreaded : + ResamplingWavFileReader::ResampleAtOnce, + ResamplingWavFileReader::CacheInTemporaryFile, + targetRate, + reporter); + } + + if (!reader->isOK()) { + delete reader; + reader = 0; + } + } + +#ifdef HAVE_OGGZ +#ifdef HAVE_FISHSOUND + if (!reader) { + reader = new OggVorbisFileReader + (source, + threading ? + OggVorbisFileReader::DecodeThreaded : + OggVorbisFileReader::DecodeAtOnce, + OggVorbisFileReader::CacheInTemporaryFile, + targetRate, + reporter); + + if (!reader->isOK()) { + delete reader; + reader = 0; + } + } +#endif +#endif + +#ifdef HAVE_MAD + if (!reader) { + reader = new MP3FileReader + (source, + threading ? + MP3FileReader::DecodeThreaded : + MP3FileReader::DecodeAtOnce, + MP3FileReader::CacheInTemporaryFile, + targetRate, + reporter); + + if (!reader->isOK()) { + delete reader; + reader = 0; + } + } +#endif + +#ifdef HAVE_QUICKTIME + if (!reader) { + reader = new QuickTimeFileReader + (source, + threading ? + QuickTimeFileReader::DecodeThreaded : + QuickTimeFileReader::DecodeAtOnce, + QuickTimeFileReader::CacheInTemporaryFile, + targetRate, + reporter); + + if (!reader->isOK()) { + delete reader; + reader = 0; } } #endif
--- a/data/fileio/PlaylistFileReader.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/data/fileio/PlaylistFileReader.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -18,6 +18,10 @@ #include <QFile> #include <QTextStream> #include <QStringList> +#include <QFileInfo> +#include <QDir> + +#include <iostream> PlaylistFileReader::PlaylistFileReader(QString path) : m_source(path), @@ -56,7 +60,9 @@ m_source.waitForData(); - m_file = new QFile(m_source.getLocalFilename()); + QString filename = m_source.getLocalFilename(); + + m_file = new QFile(filename); bool good = false; if (!m_file->exists()) { @@ -69,6 +75,12 @@ good = true; } + if (good) { + if (!m_source.isRemote()) { + m_basedir = QFileInfo(filename).dir().canonicalPath(); + } + } + if (!good) { delete m_file; m_file = 0; @@ -105,12 +117,31 @@ QString chunk = in.readLine(); QStringList lines = chunk.split('\r', QString::SkipEmptyParts); - for (size_t li = 0; li < lines.size(); ++li) { + for (int li = 0; li < lines.size(); ++li) { QString line = lines[li]; if (line.startsWith("#")) continue; + // line is expected to be a URL or a file path. If it + // appears to be a local relative file path, then we + // should check whether it can be resolved relative to the + // location of the playlist file and, if so, do so. + + if (!FileSource::isRemote(line)) { + if (QFileInfo(line).isRelative() && m_basedir != "") { + QString testpath = QDir(m_basedir).filePath(line); + if (QFileInfo(testpath).exists() && + QFileInfo(testpath).isFile()) { + std::cerr << "Path \"" << line.toStdString() + << "\" is relative, resolving to \"" + << testpath.toStdString() << "\"" + << std::endl; + line = testpath; + } + } + } + playlist.push_back(line); } }
--- a/data/fileio/PlaylistFileReader.h Thu Sep 18 12:09:32 2008 +0000 +++ b/data/fileio/PlaylistFileReader.h Thu Sep 18 12:33:30 2008 +0000 @@ -45,6 +45,7 @@ FileSource m_source; QFile *m_file; + QString m_basedir; QString m_error; };
--- a/rdf/PluginRDFDescription.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/PluginRDFDescription.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -53,15 +53,6 @@ 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 { @@ -72,16 +63,6 @@ } 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) == @@ -92,6 +73,26 @@ } QString +PluginRDFDescription::getOutputFeatureAttributeURI(QString outputId) const +{ + if (m_outputFeatureAttributeURIMap.find(outputId) == + m_outputFeatureAttributeURIMap.end()) { + return ""; + } + return m_outputFeatureAttributeURIMap.find(outputId)->second; +} + +QString +PluginRDFDescription::getOutputSignalTypeURI(QString outputId) const +{ + if (m_outputSignalTypeURIMap.find(outputId) == + m_outputSignalTypeURIMap.end()) { + return ""; + } + return m_outputSignalTypeURIMap.find(outputId)->second; +} + +QString PluginRDFDescription::getOutputUnit(QString outputId) const { if (m_outputUnitMap.find(outputId) == m_outputUnitMap.end()) { @@ -111,27 +112,19 @@ ( " PREFIX vamp: <http://purl.org/ontology/vamp/> " - " SELECT ?output_id ?output_type ?feature_type ?event_type ?unit " + " SELECT ?output ?output_id ?output_type ?unit " " FROM <%1> " " WHERE { " " ?plugin a vamp:Plugin ; " " vamp:identifier \"%2\" ; " - " vamp:output_descriptor ?output . " + " vamp:output ?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 " " } . " @@ -152,7 +145,8 @@ if (results.empty()) { cerr << "ERROR: PluginRDFDescription::indexURL: NOTE: Document at <" << url.toStdString() - << "> does not appear to describe any plugin outputs" << endl; + << "> does not appear to describe any outputs for plugin with id \"" + << label.toStdString() << "\"" << endl; return false; } @@ -162,12 +156,8 @@ for (int i = 0; i < results.size(); ++i) { + QString outputUri = results[i]["output"].value; 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")) { @@ -177,34 +167,6 @@ } 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) { @@ -214,6 +176,35 @@ m_outputUnitMap[outputId] = unit; } } + + QString queryTemplate = + QString(" PREFIX vamp: <http://purl.org/ontology/vamp/> " + " SELECT ?%3 FROM <%1> " + " WHERE { <%2> vamp:computes_%3 ?%3 } ") + .arg(url).arg(outputUri); + + SimpleSPARQLQuery::Value v; + + v = SimpleSPARQLQuery::singleResultQuery + (queryTemplate.arg("event_type"), "event_type"); + + if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { + m_outputEventTypeURIMap[outputId] = v.value; + } + + v = SimpleSPARQLQuery::singleResultQuery + (queryTemplate.arg("feature_attribute"), "feature_attribute"); + + if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { + m_outputFeatureAttributeURIMap[outputId] = v.value; + } + + v = SimpleSPARQLQuery::singleResultQuery + (queryTemplate.arg("signal_type"), "signal_type"); + + if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") { + m_outputSignalTypeURIMap[outputId] = v.value; + } } return true;
--- a/rdf/PluginRDFDescription.h Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/PluginRDFDescription.h Thu Sep 18 12:33:30 2008 +0000 @@ -28,14 +28,6 @@ PluginRDFDescription(QString pluginId); ~PluginRDFDescription(); - enum OutputType - { - OutputTypeUnknown, - OutputFeatures, - OutputEvents, - OutputFeaturesAndEvents - }; - enum OutputDisposition { OutputDispositionUnknown, @@ -45,23 +37,22 @@ }; bool haveDescription() const; - OutputType getOutputType(QString outputId) const; OutputDisposition getOutputDisposition(QString outputId) const; - QString getOutputFeatureTypeURI(QString outputId) const; QString getOutputEventTypeURI(QString outputId) const; + QString getOutputFeatureAttributeURI(QString outputId) const; + QString getOutputSignalTypeURI(QString outputId) const; QString getOutputUnit(QString outputId) const; protected: - typedef std::map<QString, OutputType> OutputTypeMap; typedef std::map<QString, OutputDisposition> OutputDispositionMap; typedef std::map<QString, QString> OutputStringMap; QString m_pluginId; bool m_haveDescription; - OutputTypeMap m_outputTypes; OutputDispositionMap m_outputDispositions; - OutputStringMap m_outputFeatureTypeURIMap; OutputStringMap m_outputEventTypeURIMap; + OutputStringMap m_outputFeatureAttributeURIMap; + OutputStringMap m_outputSignalTypeURIMap; OutputStringMap m_outputUnitMap; bool indexURL(QString url); };
--- a/rdf/PluginRDFIndexer.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/PluginRDFIndexer.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -181,7 +181,12 @@ // 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 } . " + //!!! No -- because of rasqal's inability to correctly + // handle more than one OPTIONAL graph in a query, let's + // make identifier compulsory after all + //" OPTIONAL { ?plugin vamp:identifier ?plugin_id } . " + + " ?plugin vamp:identifier ?plugin_id . " " OPTIONAL { " " ?library a vamp:PluginLibrary ; "
--- a/rdf/RDFImporter.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/RDFImporter.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -54,6 +54,13 @@ typedef std::map<QString, TimeValueMap> TypeTimeValueMap; typedef std::map<QString, TypeTimeValueMap> SourceTypeTimeValueMap; + void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *); + void getDataModelsDense(std::vector<Model *> &, ProgressReporter *); + + void getDenseFeatureProperties(QString featureUri, + int &sampleRate, int &windowLength, + int &hopSize, int &width, int &height); + void extractStructure(const TimeValueMap &map, bool &sparse, int &minValueCount, int &maxValueCount); @@ -124,6 +131,229 @@ { std::vector<Model *> models; + getDataModelsDense(models, reporter); + + QString error; + if (!isOK()) error = m_errorString; + m_errorString = ""; + + getDataModelsSparse(models, reporter); + + if (isOK()) m_errorString = error; + + return models; +} + +void +RDFImporterImpl::getDataModelsDense(std::vector<Model *> &models, + ProgressReporter *reporter) +{ + SimpleSPARQLQuery query = SimpleSPARQLQuery + (QString + ( + " PREFIX mo: <http://purl.org/ontology/mo/>" + " PREFIX af: <http://purl.org/ontology/af/>" + + " SELECT ?feature ?signal_source ?feature_signal_type ?value " + " FROM <%1> " + + " WHERE { " + + " ?signal a mo:Signal ; " + " mo:available_as ?signal_source ; " + " af:signal_feature ?feature . " + + " ?feature a ?feature_signal_type ; " + " af:value ?value . " + + " } " + ) + .arg(m_uristring)); + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + m_errorString = query.getErrorString(); + return; + } + + if (query.wasCancelled()) { + m_errorString = "Query cancelled"; + return; + } + + for (int i = 0; i < results.size(); ++i) { + + QString feature = results[i]["feature"].value; + QString source = results[i]["signal_source"].value; + QString type = results[i]["feature_signal_type"].value; + QString value = results[i]["value"].value; + + int sampleRate = 0; + int windowLength = 0; + int hopSize = 0; + int width = 0; + int height = 0; + getDenseFeatureProperties + (feature, sampleRate, windowLength, hopSize, width, height); + + if (sampleRate != 0 && sampleRate != m_sampleRate) { + cerr << "WARNING: Sample rate in dense feature description does not match our underlying rate -- using rate from feature description" << endl; + } + if (sampleRate == 0) sampleRate = m_sampleRate; + + if (hopSize == 0) { + cerr << "WARNING: Dense feature description does not specify a hop size -- assuming 1" << endl; + hopSize = 1; + } + + if (height == 0) { + cerr << "WARNING: Dense feature description does not specify feature signal dimensions -- assuming one-dimensional (height = 1)" << endl; + height = 1; + } + + QStringList values = value.split(' ', QString::SkipEmptyParts); + + if (values.empty()) { + cerr << "WARNING: Dense feature description does not specify any values!" << endl; + continue; + } + + if (height == 1) { + + SparseTimeValueModel *m = new SparseTimeValueModel + (sampleRate, hopSize, false); + + for (int j = 0; j < values.size(); ++j) { + float f = values[j].toFloat(); + SparseTimeValueModel::Point point(j * hopSize, f, ""); + m->addPoint(point); + } + + models.push_back(m); + + } else { + + EditableDenseThreeDimensionalModel *m = + new EditableDenseThreeDimensionalModel(sampleRate, hopSize, + height, false); + + EditableDenseThreeDimensionalModel::Column column; + + int x = 0; + + for (int j = 0; j < values.size(); ++j) { + if (j % height == 0 && !column.empty()) { + m->setColumn(x++, column); + column.clear(); + } + column.push_back(values[j].toFloat()); + } + + if (!column.empty()) { + m->setColumn(x++, column); + } + + models.push_back(m); + } + } +} + +void +RDFImporterImpl::getDenseFeatureProperties(QString featureUri, + int &sampleRate, int &windowLength, + int &hopSize, int &width, int &height) +{ + QString dimensionsQuery + ( + " PREFIX mo: <http://purl.org/ontology/mo/>" + " PREFIX af: <http://purl.org/ontology/af/>" + + " SELECT ?dimensions " + " FROM <%1> " + + " WHERE { " + + " <%2> af:dimensions ?dimensions . " + + " } " + ); + + SimpleSPARQLQuery::Value dimensionsValue = + SimpleSPARQLQuery::singleResultQuery(dimensionsQuery + .arg(m_uristring).arg(featureUri), + "dimensions"); + + cerr << "Dimensions = \"" << dimensionsValue.value.toStdString() << "\"" + << endl; + + if (dimensionsValue.value != "") { + QStringList dl = dimensionsValue.value.split(" "); + if (dl.empty()) dl.push_back(dimensionsValue.value); + if (dl.size() > 0) height = dl[0].toInt(); + if (dl.size() > 1) width = dl[1].toInt(); + } + + QString queryTemplate + ( + " PREFIX mo: <http://purl.org/ontology/mo/>" + " PREFIX af: <http://purl.org/ontology/af/>" + " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>" + + " SELECT ?%3 " + " FROM <%1> " + + " WHERE { " + + " <%2> mo:time ?time . " + + " ?time a tl:Interval ; " + " tl:onTimeLine ?timeline . " + + " ?map tl:rangeTimeLine ?timeline . " + + " ?map tl:%3 ?%3 . " + + " } " + ); + + // Another laborious workaround for rasqal's failure to handle + // multiple optionals properly + + SimpleSPARQLQuery::Value srValue = + SimpleSPARQLQuery::singleResultQuery(queryTemplate + .arg(m_uristring).arg(featureUri) + .arg("sampleRate"), + "sampleRate"); + if (srValue.value != "") { + sampleRate = srValue.value.toInt(); + } + + SimpleSPARQLQuery::Value hopValue = + SimpleSPARQLQuery::singleResultQuery(queryTemplate + .arg(m_uristring).arg(featureUri) + .arg("hopSize"), + "hopSize"); + if (srValue.value != "") { + hopSize = hopValue.value.toInt(); + } + + SimpleSPARQLQuery::Value winValue = + SimpleSPARQLQuery::singleResultQuery(queryTemplate + .arg(m_uristring).arg(featureUri) + .arg("windowLength"), + "windowLength"); + if (winValue.value != "") { + windowLength = winValue.value.toInt(); + } + + cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl; +} + +void +RDFImporterImpl::getDataModelsSparse(std::vector<Model *> &models, + ProgressReporter *reporter) +{ // 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. @@ -163,20 +393,23 @@ " PREFIX mo: <http://purl.org/ontology/mo/>" " PREFIX af: <http://purl.org/ontology/af/>" - " SELECT ?signalSource ?time ?eventType ?value" + " SELECT ?signal_source ?time ?event_type ?value" " FROM <%1>" " WHERE {" - " ?signal mo:available_as ?signalSource ." + + " ?signal mo:available_as ?signal_source ." + " ?signal a mo:Signal ." + " ?signal mo:time ?interval ." " ?interval time:onTimeLine ?tl ." " ?t time:onTimeLine ?tl ." " ?t time:at ?time ." - " ?timedThing event:time ?t ." - " ?timedThing a ?eventType ." + " ?timed_thing event:time ?t ." + " ?timed_thing a ?event_type ." + " OPTIONAL {" - " ?timedThing af:hasFeature ?feature ." - " ?feature af:value ?value" + " ?timed_thing af:feature ?value" " }" " }" @@ -191,17 +424,17 @@ if (!query.isOK()) { m_errorString = query.getErrorString(); - return models; + return; } if (query.wasCancelled()) { m_errorString = "Query cancelled"; - return models; + return; } for (int i = 0; i < results.size(); ++i) { - QString source = results[i]["signalSource"].value; + QString source = results[i]["signal_source"].value; QString timestring = results[i]["time"].value; RealTime time; @@ -209,12 +442,13 @@ cerr << "time = " << time.toString() << " (from xsd:duration \"" << timestring.toStdString() << "\")" << endl; - QString type = results[i]["eventType"].value; + QString type = results[i]["event_type"].value; QString valuestring = results[i]["value"].value; float value = 0.f; bool haveValue = false; if (valuestring != "") { + //!!! no -- runner actually writes a "CSV literal" value = valuestring.toFloat(&haveValue); cerr << "value = " << value << endl; } @@ -322,9 +556,6 @@ } } } - - - return models; } void
--- a/rdf/RDFTransformFactory.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/RDFTransformFactory.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -18,9 +18,6 @@ #include <map> #include <vector> -#include <redland.h> -#include <rasqal.h> - #include <iostream> #include <cmath> @@ -50,6 +47,8 @@ protected: QString m_urlString; QString m_errorString; + bool setOutput(Transform &, QString, QString); + bool setParameters(Transform &, QString, QString); }; @@ -113,140 +112,156 @@ { std::vector<Transform> transforms; - SimpleSPARQLQuery query - (QString - ( - " PREFIX vamp: <http://purl.org/ontology/vamp/> " + // We have to do this a very long way round, to work around + // rasqal's current inability to handle correctly more than one + // OPTIONAL graph in a query - " SELECT ?transform ?plugin ?output ?program " - " ?step_size ?block_size ?window_type " - " ?sample_rate ?start ?duration " + const char *optionals[] = { + "output", + "program", + "step_size", + "block_size", + "window_type", + "sample_rate", + "start", + "duration" + }; - " FROM <%1> " + std::map<QString, Transform> uriTransformMap; - " 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)); + QString queryTemplate = + " PREFIX vamp: <http://purl.org/ontology/vamp/> " - SimpleSPARQLQuery::ResultList results = query.execute(); + " SELECT ?transform ?plugin %1 " + + " FROM <%2> " - if (!query.isOK()) { - m_errorString = query.getErrorString(); + " WHERE { " + " ?transform a vamp:Transform ; " + " vamp:plugin ?plugin . " + " %3 " + " } "; + + SimpleSPARQLQuery transformsQuery + (queryTemplate.arg("").arg(m_urlString).arg("")); + + SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute(); + + if (!transformsQuery.isOK()) { + m_errorString = transformsQuery.getErrorString(); return transforms; } - if (query.wasCancelled()) { - m_errorString = "Query cancelled"; + if (transformResults.empty()) { + cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl; return transforms; } PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); - for (int i = 0; i < results.size(); ++i) { + for (int i = 0; i < transformResults.size(); ++i) { - SimpleSPARQLQuery::KeyValueMap &result = results[i]; + SimpleSPARQLQuery::KeyValueMap &result = transformResults[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() << ">, skipping this transform" + << endl; + continue; + } + + QString pluginDescriptionURL = + indexer->getDescriptionURLForPluginId(pluginId); + if (pluginDescriptionURL == "") { + cerr << "RDFTransformFactory: WARNING: No RDF description available for plugin <" + << pluginUri.toStdString() << ">, skipping 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: <http://purl.org/ontology/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(); + if (!setOutput(transform, transformUri, pluginDescriptionURL)) { return transforms; } - if (paramQuery.wasCancelled()) { - m_errorString = "Query cancelled"; + if (!setParameters(transform, transformUri, pluginDescriptionURL)) { return transforms; } - for (int j = 0; j < paramResults.size(); ++j) { + uriTransformMap[transformUri] = transform; + } - QString paramId = paramResults[j]["param_id"].value; - QString paramValue = paramResults[j]["param_value"].value; + for (int i = 0; i < sizeof(optionals)/sizeof(optionals[0]); ++i) { - if (paramId == "" || paramValue == "") continue; + QString optional = optionals[i]; - transform.setParameter(paramId, paramValue.toFloat()); + SimpleSPARQLQuery query + (queryTemplate + .arg(QString("?%1").arg(optional)) + .arg(m_urlString) + .arg(QString("?transform vamp:%1 ?%2") + .arg(optionals[i]).arg(optional))); + + SimpleSPARQLQuery::ResultList results = query.execute(); + + if (!query.isOK()) { + m_errorString = query.getErrorString(); + return transforms; } + if (results.empty()) continue; + + for (int j = 0; j < results.size(); ++j) { + + QString transformUri = results[j]["transform"].value; + + if (uriTransformMap.find(transformUri) == uriTransformMap.end()) { + cerr << "RDFTransformFactory: ERROR: Transform URI <" + << transformUri.toStdString() << "> not found in internal map!" << endl; + continue; + } + + Transform &transform = uriTransformMap[transformUri]; + const SimpleSPARQLQuery::Value &v = results[j][optional]; + + if (v.type == SimpleSPARQLQuery::LiteralValue) { + + if (optional == "program") { + transform.setProgram(v.value); + } else if (optional == "step_size") { + transform.setStepSize(v.value.toUInt()); + } else if (optional == "block_size") { + transform.setBlockSize(v.value.toUInt()); + } else if (optional == "window_type") { + cerr << "NOTE: can't handle window type yet (value is \"" + << v.value.toStdString() << "\")" << endl; + } else if (optional == "sample_rate") { + transform.setSampleRate(v.value.toFloat()); + } else if (optional == "start") { + transform.setStartTime + (RealTime::fromXsdDuration(v.value.toStdString())); + } else if (optional == "duration") { + transform.setDuration + (RealTime::fromXsdDuration(v.value.toStdString())); + } else { + cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl; + } + } + } + } + + for (std::map<QString, Transform>::iterator i = uriTransformMap.begin(); + i != uriTransformMap.end(); ++i) { + + Transform &transform = i->second; + cerr << "RDFTransformFactory: NOTE: Transform is: " << endl; cerr << transform.toXmlString().toStdString() << endl; @@ -256,3 +271,99 @@ return transforms; } +bool +RDFTransformFactoryImpl::setOutput(Transform &transform, + QString transformUri, + QString pluginDescriptionURL) +{ + SimpleSPARQLQuery outputQuery + (QString + ( + " PREFIX vamp: <http://purl.org/ontology/vamp/> " + + " SELECT ?output_id " + + " FROM <%1> " + " FROM <%2> " + + " WHERE { " + " <%3> vamp:output ?output . " + " ?output vamp:identifier ?output_id " + " } " + ) + .arg(m_urlString) + .arg(pluginDescriptionURL) + .arg(transformUri)); + + SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute(); + + if (!outputQuery.isOK()) { + m_errorString = outputQuery.getErrorString(); + return false; + } + + if (outputQuery.wasCancelled()) { + m_errorString = "Query cancelled"; + return false; + } + + for (int j = 0; j < outputResults.size(); ++j) { + QString outputId = outputResults[j]["output_id"].value; + transform.setOutput(outputId); + } + + return true; +} + + +bool +RDFTransformFactoryImpl::setParameters(Transform &transform, + QString transformUri, + QString pluginDescriptionURL) +{ + SimpleSPARQLQuery paramQuery + (QString + ( + " PREFIX vamp: <http://purl.org/ontology/vamp/> " + + " SELECT ?param_id ?param_value " + + " FROM <%1> " + " FROM <%2> " + + " WHERE { " + " <%3> vamp:parameter_binding ?binding . " + " ?binding vamp:parameter ?param ; " + " vamp:value ?param_value . " + " ?param vamp:identifier ?param_id " + " } " + ) + .arg(m_urlString) + .arg(pluginDescriptionURL) + .arg(transformUri)); + + SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute(); + + if (!paramQuery.isOK()) { + m_errorString = paramQuery.getErrorString(); + return false; + } + + if (paramQuery.wasCancelled()) { + m_errorString = "Query cancelled"; + return false; + } + + 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()); + } + + return true; +} +
--- a/rdf/SimpleSPARQLQuery.cpp Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/SimpleSPARQLQuery.cpp Thu Sep 18 12:33:30 2008 +0000 @@ -16,13 +16,31 @@ #include "SimpleSPARQLQuery.h" #include "base/ProgressReporter.h" +#ifdef USE_NEW_RASQAL_API +#include <rasqal/rasqal.h> +#else #include <rasqal.h> +#endif #include <iostream> using std::cerr; using std::endl; +#ifdef USE_NEW_RASQAL_API +class WrasqalWorldWrapper // wrong but wromantic, etc +{ +public: + WrasqalWorldWrapper() : m_world(rasqal_new_world()) { } + ~WrasqalWorldWrapper() { rasqal_free_world(m_world); } + + rasqal_world *getWorld() const { return m_world; } + +private: + rasqal_world *m_world; +}; +#endif + class SimpleSPARQLQuery::Impl { public: @@ -40,7 +58,11 @@ protected: static void errorHandler(void *, raptor_locator *, const char *); +#ifdef USE_NEW_RASQAL_API + static WrasqalWorldWrapper m_www; +#else static bool m_initialised; +#endif QString m_query; QString m_errorString; @@ -48,6 +70,14 @@ bool m_cancelled; }; +#ifdef USE_NEW_RASQAL_API +WrasqalWorldWrapper +SimpleSPARQLQuery::Impl::m_www; +#else +bool +SimpleSPARQLQuery::Impl::m_initialised = false; +#endif + SimpleSPARQLQuery::SimpleSPARQLQuery(QString query) : m_impl(new Impl(query)) { } @@ -86,23 +116,15 @@ 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 @@ -138,7 +160,15 @@ { ResultList list; +#ifdef USE_NEW_RASQAL_API + rasqal_query *query = rasqal_new_query(m_www.getWorld(), "sparql", NULL); +#else + if (!m_initialised) { + m_initialised = true; + rasqal_init(); + } rasqal_query *query = rasqal_new_query("sparql", NULL); +#endif if (!query) { m_errorString = "Failed to construct query"; cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl; @@ -232,4 +262,28 @@ return list; } - + +SimpleSPARQLQuery::Value +SimpleSPARQLQuery::singleResultQuery(QString query, QString binding) +{ + SimpleSPARQLQuery q(query); + ResultList results = q.execute(); + if (!q.isOK()) { + cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: " + << q.getErrorString().toStdString() << endl; + return Value(); + } + if (results.empty()) { + return Value(); + } + for (int i = 0; i < results.size(); ++i) { + if (results[i].find(binding) != results[i].end() && + results[i][binding].type != NoValue) { + return results[i][binding]; + } + } + return Value(); +} + + +
--- a/rdf/SimpleSPARQLQuery.h Thu Sep 18 12:09:32 2008 +0000 +++ b/rdf/SimpleSPARQLQuery.h Thu Sep 18 12:33:30 2008 +0000 @@ -48,6 +48,10 @@ bool isOK() const; QString getErrorString() const; + // Do a query and return the value for the given binding, from the + // first result that has a value for it + static Value singleResultQuery(QString query, QString binding); + protected: class Impl; Impl *m_impl;