annotate rdf/RDFTransformFactory.cpp @ 449:a75edaa08d28

* Support importing features from RDF whose times are intervals rather than only instants; import them into region or note models. Sadly this makes RDF import much, much slower, because we need to work around Rasqal's single-OPTIONAL limitation by repeatedly querying each feature for time and range. * Add segmentation view to region layer, and display label texts
author Chris Cannam
date Tue, 07 Oct 2008 12:42:17 +0000
parents 5746c559af15
children 3ffce691c9bf
rev   line source
Chris@439 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@439 2
Chris@439 3 /*
Chris@439 4 Sonic Visualiser
Chris@439 5 An audio file viewer and annotation editor.
Chris@439 6 Centre for Digital Music, Queen Mary, University of London.
Chris@439 7 This file copyright 2008 QMUL.
Chris@439 8
Chris@439 9 This program is free software; you can redistribute it and/or
Chris@439 10 modify it under the terms of the GNU General Public License as
Chris@439 11 published by the Free Software Foundation; either version 2 of the
Chris@439 12 License, or (at your option) any later version. See the file
Chris@439 13 COPYING included with this distribution for more information.
Chris@439 14 */
Chris@439 15
Chris@439 16 #include "RDFTransformFactory.h"
Chris@439 17
Chris@439 18 #include <map>
Chris@439 19 #include <vector>
Chris@439 20
Chris@439 21 #include <iostream>
Chris@439 22 #include <cmath>
Chris@439 23
Chris@439 24 #include "SimpleSPARQLQuery.h"
Chris@439 25 #include "PluginRDFIndexer.h"
Chris@439 26 #include "base/ProgressReporter.h"
Chris@439 27
Chris@439 28 #include "transform/TransformFactory.h"
Chris@439 29
Chris@439 30 using std::cerr;
Chris@439 31 using std::endl;
Chris@439 32
Chris@439 33 typedef const unsigned char *STR; // redland's expected string type
Chris@439 34
Chris@439 35
Chris@439 36 class RDFTransformFactoryImpl
Chris@439 37 {
Chris@439 38 public:
Chris@439 39 RDFTransformFactoryImpl(QString url);
Chris@439 40 virtual ~RDFTransformFactoryImpl();
Chris@439 41
Chris@439 42 bool isOK();
Chris@439 43 QString getErrorString() const;
Chris@439 44
Chris@439 45 std::vector<Transform> getTransforms(ProgressReporter *);
Chris@439 46
Chris@439 47 protected:
Chris@439 48 QString m_urlString;
Chris@439 49 QString m_errorString;
Chris@440 50 bool setOutput(Transform &, QString, QString);
Chris@440 51 bool setParameters(Transform &, QString, QString);
Chris@439 52 };
Chris@439 53
Chris@439 54
Chris@439 55 QString
Chris@439 56 RDFTransformFactory::getKnownExtensions()
Chris@439 57 {
Chris@439 58 return "*.rdf *.n3 *.ttl";
Chris@439 59 }
Chris@439 60
Chris@439 61 RDFTransformFactory::RDFTransformFactory(QString url) :
Chris@439 62 m_d(new RDFTransformFactoryImpl(url))
Chris@439 63 {
Chris@439 64 }
Chris@439 65
Chris@439 66 RDFTransformFactory::~RDFTransformFactory()
Chris@439 67 {
Chris@439 68 delete m_d;
Chris@439 69 }
Chris@439 70
Chris@439 71 bool
Chris@439 72 RDFTransformFactory::isOK()
Chris@439 73 {
Chris@439 74 return m_d->isOK();
Chris@439 75 }
Chris@439 76
Chris@439 77 QString
Chris@439 78 RDFTransformFactory::getErrorString() const
Chris@439 79 {
Chris@439 80 return m_d->getErrorString();
Chris@439 81 }
Chris@439 82
Chris@439 83 std::vector<Transform>
Chris@439 84 RDFTransformFactory::getTransforms(ProgressReporter *r)
Chris@439 85 {
Chris@439 86 return m_d->getTransforms(r);
Chris@439 87 }
Chris@439 88
Chris@439 89 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) :
Chris@439 90 m_urlString(url)
Chris@439 91 {
Chris@439 92 }
Chris@439 93
Chris@439 94 RDFTransformFactoryImpl::~RDFTransformFactoryImpl()
Chris@439 95 {
Chris@439 96 }
Chris@439 97
Chris@439 98 bool
Chris@439 99 RDFTransformFactoryImpl::isOK()
Chris@439 100 {
Chris@439 101 return (m_errorString == "");
Chris@439 102 }
Chris@439 103
Chris@439 104 QString
Chris@439 105 RDFTransformFactoryImpl::getErrorString() const
Chris@439 106 {
Chris@439 107 return m_errorString;
Chris@439 108 }
Chris@439 109
Chris@439 110 std::vector<Transform>
Chris@439 111 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter)
Chris@439 112 {
Chris@439 113 std::vector<Transform> transforms;
Chris@439 114
Chris@440 115 // We have to do this a very long way round, to work around
Chris@440 116 // rasqal's current inability to handle correctly more than one
Chris@440 117 // OPTIONAL graph in a query
Chris@439 118
Chris@440 119 const char *optionals[] = {
Chris@440 120 "output",
Chris@440 121 "program",
Chris@440 122 "step_size",
Chris@440 123 "block_size",
Chris@440 124 "window_type",
Chris@440 125 "sample_rate",
Chris@440 126 "start",
Chris@440 127 "duration"
Chris@440 128 };
Chris@439 129
Chris@440 130 std::map<QString, Transform> uriTransformMap;
Chris@439 131
Chris@440 132 QString queryTemplate =
Chris@440 133 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@439 134
Chris@440 135 " SELECT ?transform ?plugin %1 "
Chris@440 136
Chris@440 137 " FROM <%2> "
Chris@439 138
Chris@440 139 " WHERE { "
Chris@440 140 " ?transform a vamp:Transform ; "
Chris@440 141 " vamp:plugin ?plugin . "
Chris@440 142 " %3 "
Chris@440 143 " } ";
Chris@440 144
Chris@440 145 SimpleSPARQLQuery transformsQuery
Chris@440 146 (queryTemplate.arg("").arg(m_urlString).arg(""));
Chris@440 147
Chris@440 148 SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute();
Chris@440 149
Chris@440 150 if (!transformsQuery.isOK()) {
Chris@440 151 m_errorString = transformsQuery.getErrorString();
Chris@439 152 return transforms;
Chris@439 153 }
Chris@439 154
Chris@440 155 if (transformResults.empty()) {
Chris@440 156 cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl;
Chris@439 157 return transforms;
Chris@439 158 }
Chris@439 159
Chris@439 160 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@439 161
Chris@440 162 for (int i = 0; i < transformResults.size(); ++i) {
Chris@439 163
Chris@440 164 SimpleSPARQLQuery::KeyValueMap &result = transformResults[i];
Chris@439 165
Chris@439 166 QString transformUri = result["transform"].value;
Chris@439 167 QString pluginUri = result["plugin"].value;
Chris@439 168
Chris@439 169 QString pluginId = indexer->getIdForPluginURI(pluginUri);
Chris@439 170 if (pluginId == "") {
Chris@439 171 cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
Chris@439 172 << pluginUri.toStdString() << "> for transform <"
Chris@440 173 << transformUri.toStdString() << ">, skipping this transform"
Chris@440 174 << endl;
Chris@440 175 continue;
Chris@440 176 }
Chris@440 177
Chris@440 178 QString pluginDescriptionURL =
Chris@440 179 indexer->getDescriptionURLForPluginId(pluginId);
Chris@440 180 if (pluginDescriptionURL == "") {
Chris@440 181 cerr << "RDFTransformFactory: WARNING: No RDF description available for plugin <"
Chris@440 182 << pluginUri.toStdString() << ">, skipping transform <"
Chris@439 183 << transformUri.toStdString() << ">" << endl;
Chris@439 184 continue;
Chris@439 185 }
Chris@439 186
Chris@439 187 Transform transform;
Chris@439 188 transform.setPluginIdentifier(pluginId);
Chris@439 189
Chris@440 190 if (!setOutput(transform, transformUri, pluginDescriptionURL)) {
Chris@439 191 return transforms;
Chris@439 192 }
Chris@439 193
Chris@440 194 if (!setParameters(transform, transformUri, pluginDescriptionURL)) {
Chris@439 195 return transforms;
Chris@439 196 }
Chris@439 197
Chris@440 198 uriTransformMap[transformUri] = transform;
Chris@440 199 }
Chris@439 200
Chris@440 201 for (int i = 0; i < sizeof(optionals)/sizeof(optionals[0]); ++i) {
Chris@439 202
Chris@440 203 QString optional = optionals[i];
Chris@439 204
Chris@440 205 SimpleSPARQLQuery query
Chris@440 206 (queryTemplate
Chris@440 207 .arg(QString("?%1").arg(optional))
Chris@440 208 .arg(m_urlString)
Chris@440 209 .arg(QString("?transform vamp:%1 ?%2")
Chris@440 210 .arg(optionals[i]).arg(optional)));
Chris@440 211
Chris@440 212 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@440 213
Chris@440 214 if (!query.isOK()) {
Chris@440 215 m_errorString = query.getErrorString();
Chris@440 216 return transforms;
Chris@439 217 }
Chris@439 218
Chris@440 219 if (results.empty()) continue;
Chris@440 220
Chris@440 221 for (int j = 0; j < results.size(); ++j) {
Chris@440 222
Chris@440 223 QString transformUri = results[j]["transform"].value;
Chris@440 224
Chris@440 225 if (uriTransformMap.find(transformUri) == uriTransformMap.end()) {
Chris@440 226 cerr << "RDFTransformFactory: ERROR: Transform URI <"
Chris@440 227 << transformUri.toStdString() << "> not found in internal map!" << endl;
Chris@440 228 continue;
Chris@440 229 }
Chris@440 230
Chris@440 231 Transform &transform = uriTransformMap[transformUri];
Chris@440 232 const SimpleSPARQLQuery::Value &v = results[j][optional];
Chris@440 233
Chris@440 234 if (v.type == SimpleSPARQLQuery::LiteralValue) {
Chris@440 235
Chris@440 236 if (optional == "program") {
Chris@440 237 transform.setProgram(v.value);
Chris@440 238 } else if (optional == "step_size") {
Chris@440 239 transform.setStepSize(v.value.toUInt());
Chris@440 240 } else if (optional == "block_size") {
Chris@440 241 transform.setBlockSize(v.value.toUInt());
Chris@440 242 } else if (optional == "window_type") {
Chris@440 243 cerr << "NOTE: can't handle window type yet (value is \""
Chris@440 244 << v.value.toStdString() << "\")" << endl;
Chris@440 245 } else if (optional == "sample_rate") {
Chris@440 246 transform.setSampleRate(v.value.toFloat());
Chris@440 247 } else if (optional == "start") {
Chris@440 248 transform.setStartTime
Chris@440 249 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 250 } else if (optional == "duration") {
Chris@440 251 transform.setDuration
Chris@440 252 (RealTime::fromXsdDuration(v.value.toStdString()));
Chris@440 253 } else {
Chris@440 254 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl;
Chris@440 255 }
Chris@440 256 }
Chris@440 257 }
Chris@440 258 }
Chris@440 259
Chris@440 260 for (std::map<QString, Transform>::iterator i = uriTransformMap.begin();
Chris@440 261 i != uriTransformMap.end(); ++i) {
Chris@440 262
Chris@440 263 Transform &transform = i->second;
Chris@440 264
Chris@439 265 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
Chris@439 266 cerr << transform.toXmlString().toStdString() << endl;
Chris@439 267
Chris@439 268 transforms.push_back(transform);
Chris@439 269 }
Chris@439 270
Chris@439 271 return transforms;
Chris@439 272 }
Chris@439 273
Chris@440 274 bool
Chris@440 275 RDFTransformFactoryImpl::setOutput(Transform &transform,
Chris@440 276 QString transformUri,
Chris@440 277 QString pluginDescriptionURL)
Chris@440 278 {
Chris@440 279 SimpleSPARQLQuery outputQuery
Chris@440 280 (QString
Chris@440 281 (
Chris@440 282 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 283
Chris@440 284 " SELECT ?output_id "
Chris@440 285
Chris@440 286 " FROM <%1> "
Chris@440 287 " FROM <%2> "
Chris@440 288
Chris@440 289 " WHERE { "
Chris@440 290 " <%3> vamp:output ?output . "
Chris@440 291 " ?output vamp:identifier ?output_id "
Chris@440 292 " } "
Chris@440 293 )
Chris@440 294 .arg(m_urlString)
Chris@440 295 .arg(pluginDescriptionURL)
Chris@440 296 .arg(transformUri));
Chris@440 297
Chris@440 298 SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute();
Chris@440 299
Chris@440 300 if (!outputQuery.isOK()) {
Chris@440 301 m_errorString = outputQuery.getErrorString();
Chris@440 302 return false;
Chris@440 303 }
Chris@440 304
Chris@440 305 if (outputQuery.wasCancelled()) {
Chris@440 306 m_errorString = "Query cancelled";
Chris@440 307 return false;
Chris@440 308 }
Chris@440 309
Chris@440 310 for (int j = 0; j < outputResults.size(); ++j) {
Chris@440 311 QString outputId = outputResults[j]["output_id"].value;
Chris@440 312 transform.setOutput(outputId);
Chris@440 313 }
Chris@440 314
Chris@440 315 return true;
Chris@440 316 }
Chris@440 317
Chris@440 318
Chris@440 319 bool
Chris@440 320 RDFTransformFactoryImpl::setParameters(Transform &transform,
Chris@440 321 QString transformUri,
Chris@440 322 QString pluginDescriptionURL)
Chris@440 323 {
Chris@440 324 SimpleSPARQLQuery paramQuery
Chris@440 325 (QString
Chris@440 326 (
Chris@440 327 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
Chris@440 328
Chris@440 329 " SELECT ?param_id ?param_value "
Chris@440 330
Chris@440 331 " FROM <%1> "
Chris@440 332 " FROM <%2> "
Chris@440 333
Chris@440 334 " WHERE { "
Chris@440 335 " <%3> vamp:parameter_binding ?binding . "
Chris@440 336 " ?binding vamp:parameter ?param ; "
Chris@440 337 " vamp:value ?param_value . "
Chris@440 338 " ?param vamp:identifier ?param_id "
Chris@440 339 " } "
Chris@440 340 )
Chris@440 341 .arg(m_urlString)
Chris@440 342 .arg(pluginDescriptionURL)
Chris@440 343 .arg(transformUri));
Chris@440 344
Chris@440 345 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
Chris@440 346
Chris@440 347 if (!paramQuery.isOK()) {
Chris@440 348 m_errorString = paramQuery.getErrorString();
Chris@440 349 return false;
Chris@440 350 }
Chris@440 351
Chris@440 352 if (paramQuery.wasCancelled()) {
Chris@440 353 m_errorString = "Query cancelled";
Chris@440 354 return false;
Chris@440 355 }
Chris@440 356
Chris@440 357 for (int j = 0; j < paramResults.size(); ++j) {
Chris@440 358
Chris@440 359 QString paramId = paramResults[j]["param_id"].value;
Chris@440 360 QString paramValue = paramResults[j]["param_value"].value;
Chris@440 361
Chris@440 362 if (paramId == "" || paramValue == "") continue;
Chris@440 363
Chris@440 364 transform.setParameter(paramId, paramValue.toFloat());
Chris@440 365 }
Chris@440 366
Chris@440 367 return true;
Chris@440 368 }
Chris@440 369