annotate rdf/RDFTransformFactory.cpp @ 985:f073d924a7c3

Fix #1058 clicking row in Layer Edit dialog when colour 3d plot layer active jumps to wrong frame (was using sample rate where resolution intended)
author Chris Cannam
date Tue, 16 Sep 2014 10:29:19 +0100
parents 06579b8ffb7b
children a51781b11dd4
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@727 7 This file copyright 2008-2012 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@494 21 #include <QTextStream>
Chris@592 22 #include <QUrl>
Chris@494 23
Chris@439 24 #include <iostream>
Chris@439 25 #include <cmath>
Chris@439 26
Chris@439 27 #include "PluginRDFIndexer.h"
Chris@494 28 #include "PluginRDFDescription.h"
Chris@439 29 #include "base/ProgressReporter.h"
Chris@503 30 #include "plugin/PluginIdentifier.h"
Chris@439 31
Chris@439 32 #include "transform/TransformFactory.h"
Chris@439 33
Chris@727 34 #include <dataquay/BasicStore.h>
Chris@727 35 #include <dataquay/PropertyObject.h>
Chris@727 36
Chris@727 37 using Dataquay::Uri;
Chris@727 38 using Dataquay::Node;
Chris@727 39 using Dataquay::Nodes;
Chris@727 40 using Dataquay::Triple;
Chris@727 41 using Dataquay::Triples;
Chris@727 42 using Dataquay::BasicStore;
Chris@727 43 using Dataquay::PropertyObject;
Chris@439 44
Chris@439 45
Chris@439 46 class RDFTransformFactoryImpl
Chris@439 47 {
Chris@439 48 public:
Chris@439 49 RDFTransformFactoryImpl(QString url);
Chris@439 50 virtual ~RDFTransformFactoryImpl();
Chris@439 51
Chris@493 52 bool isRDF();
Chris@439 53 bool isOK();
Chris@439 54 QString getErrorString() const;
Chris@439 55
Chris@439 56 std::vector<Transform> getTransforms(ProgressReporter *);
Chris@439 57
Chris@494 58 static QString writeTransformToRDF(const Transform &, QString);
Chris@494 59
Chris@439 60 protected:
Chris@727 61 BasicStore *m_store;
Chris@439 62 QString m_urlString;
Chris@439 63 QString m_errorString;
Chris@493 64 bool m_isRDF;
Chris@489 65 bool setOutput(Transform &, QString);
Chris@489 66 bool setParameters(Transform &, QString);
Chris@439 67 };
Chris@439 68
Chris@439 69
Chris@439 70 QString
Chris@439 71 RDFTransformFactory::getKnownExtensions()
Chris@439 72 {
Chris@439 73 return "*.rdf *.n3 *.ttl";
Chris@439 74 }
Chris@439 75
Chris@439 76 RDFTransformFactory::RDFTransformFactory(QString url) :
Chris@439 77 m_d(new RDFTransformFactoryImpl(url))
Chris@439 78 {
Chris@439 79 }
Chris@439 80
Chris@439 81 RDFTransformFactory::~RDFTransformFactory()
Chris@439 82 {
Chris@439 83 delete m_d;
Chris@439 84 }
Chris@439 85
Chris@439 86 bool
Chris@493 87 RDFTransformFactory::isRDF()
Chris@493 88 {
Chris@493 89 return m_d->isRDF();
Chris@493 90 }
Chris@493 91
Chris@493 92 bool
Chris@439 93 RDFTransformFactory::isOK()
Chris@439 94 {
Chris@439 95 return m_d->isOK();
Chris@439 96 }
Chris@439 97
Chris@439 98 QString
Chris@439 99 RDFTransformFactory::getErrorString() const
Chris@439 100 {
Chris@439 101 return m_d->getErrorString();
Chris@439 102 }
Chris@439 103
Chris@439 104 std::vector<Transform>
Chris@439 105 RDFTransformFactory::getTransforms(ProgressReporter *r)
Chris@439 106 {
Chris@439 107 return m_d->getTransforms(r);
Chris@439 108 }
Chris@439 109
Chris@494 110 QString
Chris@494 111 RDFTransformFactory::writeTransformToRDF(const Transform &t, QString f)
Chris@494 112 {
Chris@494 113 return RDFTransformFactoryImpl::writeTransformToRDF(t, f);
Chris@494 114 }
Chris@494 115
Chris@439 116 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) :
Chris@727 117 m_store(new BasicStore),
Chris@493 118 m_urlString(url),
Chris@493 119 m_isRDF(false)
Chris@439 120 {
Chris@727 121 //!!! retrieve data if remote... then
Chris@727 122 m_store->addPrefix("vamp", Uri("http://purl.org/ontology/vamp/"));
Chris@727 123 try {
Chris@730 124 QUrl qurl;
Chris@730 125 if (url.startsWith("file:")) {
Chris@730 126 qurl = QUrl(url);
Chris@730 127 } else {
Chris@730 128 qurl = QUrl::fromLocalFile(url);
Chris@730 129 }
Chris@730 130 m_store->import(qurl, BasicStore::ImportIgnoreDuplicates);
Chris@727 131 m_isRDF = true;
Chris@727 132 } catch (...) { }
Chris@439 133 }
Chris@439 134
Chris@439 135 RDFTransformFactoryImpl::~RDFTransformFactoryImpl()
Chris@439 136 {
Chris@727 137 delete m_store;
Chris@439 138 }
Chris@439 139
Chris@439 140 bool
Chris@493 141 RDFTransformFactoryImpl::isRDF()
Chris@493 142 {
Chris@493 143 return m_isRDF;
Chris@493 144 }
Chris@493 145
Chris@493 146 bool
Chris@439 147 RDFTransformFactoryImpl::isOK()
Chris@439 148 {
Chris@439 149 return (m_errorString == "");
Chris@439 150 }
Chris@439 151
Chris@439 152 QString
Chris@439 153 RDFTransformFactoryImpl::getErrorString() const
Chris@439 154 {
Chris@439 155 return m_errorString;
Chris@439 156 }
Chris@439 157
Chris@439 158 std::vector<Transform>
Chris@930 159 RDFTransformFactoryImpl::getTransforms(ProgressReporter *)
Chris@439 160 {
Chris@439 161 std::vector<Transform> transforms;
Chris@439 162
Chris@440 163 std::map<QString, Transform> uriTransformMap;
Chris@439 164
Chris@727 165 Nodes tnodes = m_store->match
Chris@730 166 (Triple(Node(), Uri("a"), m_store->expand("vamp:Transform"))).subjects();
Chris@439 167
Chris@728 168 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@728 169
Chris@727 170 foreach (Node tnode, tnodes) {
Chris@439 171
Chris@730 172 Node pnode = m_store->complete
Chris@730 173 (Triple(tnode, m_store->expand("vamp:plugin"), Node()));
Chris@440 174
Chris@728 175 if (pnode == Node()) {
Chris@728 176 cerr << "RDFTransformFactory: WARNING: No vamp:plugin for "
Chris@728 177 << "vamp:Transform node " << tnode
Chris@728 178 << ", skipping this transform" << endl;
Chris@728 179 continue;
Chris@728 180 }
Chris@440 181
Chris@728 182 QString transformUri = tnode.value;
Chris@728 183 QString pluginUri = pnode.value;
Chris@439 184
Chris@439 185 QString pluginId = indexer->getIdForPluginURI(pluginUri);
Chris@439 186 if (pluginId == "") {
Chris@439 187 cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
Chris@686 188 << pluginUri << "> for transform <"
Chris@686 189 << transformUri << ">, skipping this transform"
Chris@440 190 << endl;
Chris@440 191 continue;
Chris@440 192 }
Chris@440 193
Chris@439 194 Transform transform;
Chris@439 195 transform.setPluginIdentifier(pluginId);
Chris@439 196
Chris@489 197 if (!setOutput(transform, transformUri)) {
Chris@439 198 return transforms;
Chris@439 199 }
Chris@439 200
Chris@489 201 if (!setParameters(transform, transformUri)) {
Chris@439 202 return transforms;
Chris@439 203 }
Chris@439 204
Chris@440 205 uriTransformMap[transformUri] = transform;
Chris@439 206
Chris@489 207 static const char *optionals[] = {
Chris@489 208 "program",
Chris@508 209 "summary_type",
Chris@489 210 "step_size",
Chris@489 211 "block_size",
Chris@489 212 "window_type",
Chris@489 213 "sample_rate",
Chris@489 214 "start",
Chris@489 215 "duration"
Chris@489 216 };
Chris@489 217
Chris@930 218 for (int j = 0; j < int(sizeof(optionals)/sizeof(optionals[0])); ++j) {
Chris@439 219
Chris@489 220 QString optional = optionals[j];
Chris@489 221
Chris@730 222 Node onode = m_store->complete
Chris@730 223 (Triple(Uri(transformUri),
Chris@730 224 m_store->expand(QString("vamp:") + optional), Node()));
Chris@440 225
Chris@728 226 if (onode.type != Node::Literal) continue;
Chris@440 227
Chris@728 228 if (optional == "program") {
Chris@728 229 transform.setProgram(onode.value);
Chris@728 230 } else if (optional == "summary_type") {
Chris@728 231 transform.setSummaryType
Chris@728 232 (transform.stringToSummaryType(onode.value));
Chris@728 233 } else if (optional == "step_size") {
Chris@728 234 transform.setStepSize(onode.value.toUInt());
Chris@728 235 } else if (optional == "block_size") {
Chris@728 236 transform.setBlockSize(onode.value.toUInt());
Chris@728 237 } else if (optional == "window_type") {
Chris@728 238 transform.setWindowType
Chris@728 239 (Window<float>::getTypeForName
Chris@728 240 (onode.value.toLower().toStdString()));
Chris@728 241 } else if (optional == "sample_rate") {
Chris@728 242 transform.setSampleRate(onode.value.toFloat());
Chris@728 243 } else if (optional == "start") {
Chris@728 244 transform.setStartTime
Chris@728 245 (RealTime::fromXsdDuration(onode.value.toStdString()));
Chris@728 246 } else if (optional == "duration") {
Chris@728 247 transform.setDuration
Chris@728 248 (RealTime::fromXsdDuration(onode.value.toStdString()));
Chris@728 249 } else {
Chris@728 250 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional << "\"" << endl;
Chris@440 251 }
Chris@440 252 }
Chris@440 253
Chris@730 254 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
Chris@686 255 cerr << transform.toXmlString() << endl;
Chris@439 256
Chris@439 257 transforms.push_back(transform);
Chris@439 258 }
Chris@439 259
Chris@439 260 return transforms;
Chris@439 261 }
Chris@439 262
Chris@440 263 bool
Chris@440 264 RDFTransformFactoryImpl::setOutput(Transform &transform,
Chris@489 265 QString transformUri)
Chris@440 266 {
Chris@730 267 Node outputNode = m_store->complete
Chris@730 268 (Triple(Uri(transformUri), m_store->expand("vamp:output"), Node()));
Chris@728 269
Chris@728 270 if (outputNode == Node()) return true;
Chris@489 271
Chris@728 272 if (outputNode.type != Node::URI && outputNode.type != Node::Blank) {
Chris@728 273 m_errorString = QString("vamp:output for output of transform <%1> is not a URI or blank node").arg(transformUri);
Chris@728 274 return false;
Chris@489 275 }
Chris@728 276
Chris@728 277 // Now, outputNode might be the subject of a triple within m_store
Chris@728 278 // that tells us the vamp:identifier, or it might be the subject
Chris@728 279 // of a triple within the indexer that tells us it
Chris@728 280
Chris@730 281 Node identNode = m_store->complete
Chris@730 282 (Triple(outputNode, m_store->expand("vamp:identifier"), Node()));
Chris@728 283
Chris@728 284 if (identNode == Node()) {
Chris@728 285 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@728 286 const BasicStore *index = indexer->getIndex();
Chris@730 287 identNode = index->complete
Chris@730 288 (Triple(outputNode, index->expand("vamp:identifier"), Node()));
Chris@728 289 }
Chris@728 290
Chris@728 291 if (identNode == Node() || identNode.type != Node::Literal) {
Chris@494 292 m_errorString = QString("No vamp:identifier found for output of transform <%1>, or vamp:identifier is not a literal").arg(transformUri);
Chris@489 293 return false;
Chris@489 294 }
Chris@489 295
Chris@728 296 transform.setOutput(identNode.value);
Chris@440 297
Chris@440 298 return true;
Chris@440 299 }
Chris@440 300
Chris@440 301
Chris@440 302 bool
Chris@440 303 RDFTransformFactoryImpl::setParameters(Transform &transform,
Chris@489 304 QString transformUri)
Chris@440 305 {
Chris@729 306 Nodes bindings = m_store->match
Chris@730 307 (Triple(Uri(transformUri), m_store->expand("vamp:parameter_binding"), Node())).objects();
Chris@440 308
Chris@729 309 foreach (Node binding, bindings) {
Chris@729 310
Chris@730 311 Node paramNode = m_store->complete
Chris@730 312 (Triple(binding, m_store->expand("vamp:parameter"), Node()));
Chris@729 313
Chris@729 314 if (paramNode == Node()) {
Chris@729 315 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:parameter for binding " << binding << endl;
Chris@729 316 continue;
Chris@729 317 }
Chris@729 318
Chris@730 319 Node valueNode = m_store->complete
Chris@730 320 (Triple(binding, m_store->expand("vamp:value"), Node()));
Chris@729 321
Chris@729 322 if (paramNode == Node()) {
Chris@729 323 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:value for binding " << binding << endl;
Chris@729 324 continue;
Chris@729 325 }
Chris@730 326
Chris@730 327 // As with output above, paramNode might be the subject of a
Chris@730 328 // triple within m_store that tells us the vamp:identifier, or
Chris@730 329 // it might be the subject of a triple within the indexer that
Chris@730 330 // tells us it
Chris@729 331
Chris@730 332 Node idNode = m_store->complete
Chris@730 333 (Triple(paramNode, m_store->expand("vamp:identifier"), Node()));
Chris@730 334
Chris@729 335 if (idNode == Node()) {
Chris@730 336 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
Chris@730 337 const BasicStore *index = indexer->getIndex();
Chris@730 338 idNode = index->complete
Chris@730 339 (Triple(paramNode, index->expand("vamp:identifier"), Node()));
Chris@730 340 }
Chris@730 341
Chris@730 342 if (idNode == Node() || idNode.type != Node::Literal) {
Chris@729 343 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:identifier for parameter " << paramNode << endl;
Chris@729 344 continue;
Chris@729 345 }
Chris@440 346
Chris@729 347 transform.setParameter(idNode.value, valueNode.value.toFloat());
Chris@440 348 }
Chris@440 349
Chris@440 350 return true;
Chris@440 351 }
Chris@440 352
Chris@494 353 QString
Chris@494 354 RDFTransformFactoryImpl::writeTransformToRDF(const Transform &transform,
Chris@494 355 QString uri)
Chris@494 356 {
Chris@494 357 QString str;
Chris@494 358 QTextStream s(&str);
Chris@494 359
Chris@503 360 // assumes the usual prefixes are available; requires that uri be
Chris@503 361 // a local fragment (e.g. ":transform") rather than a uri enclosed
Chris@503 362 // in <>, so that we can suffix it if need be
Chris@494 363
Chris@494 364 QString pluginId = transform.getPluginIdentifier();
Chris@494 365 QString pluginUri = PluginRDFIndexer::getInstance()->getURIForPluginId(pluginId);
Chris@494 366
Chris@503 367 if (pluginUri != "") {
Chris@503 368 s << uri << " a vamp:Transform ;" << endl;
Chris@592 369 s << " vamp:plugin <" << QUrl(pluginUri).toEncoded().data() << "> ;" << endl;
Chris@503 370 } else {
Chris@843 371 cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No plugin URI available for plugin id \"" << pluginId << "\", writing synthetic plugin and library resources" << endl;
Chris@503 372 QString type, soname, label;
Chris@503 373 PluginIdentifier::parseIdentifier(pluginId, type, soname, label);
Chris@503 374 s << uri << "_plugin a vamp:Plugin ;" << endl;
Chris@503 375 s << " vamp:identifier \"" << label << "\" .\n" << endl;
Chris@503 376 s << uri << "_library a vamp:PluginLibrary ;" << endl;
Chris@503 377 s << " vamp:identifier \"" << soname << "\" ;" << endl;
Chris@503 378 s << " vamp:available_plugin " << uri << "_plugin .\n" << endl;
Chris@503 379 s << uri << " a vamp:Transform ;" << endl;
Chris@503 380 s << " vamp:plugin " << uri << "_plugin ;" << endl;
Chris@503 381 }
Chris@503 382
Chris@494 383 PluginRDFDescription description(pluginId);
Chris@503 384 QString outputId = transform.getOutput();
Chris@503 385 QString outputUri = description.getOutputUri(outputId);
Chris@494 386
Chris@494 387 if (transform.getOutput() != "" && outputUri == "") {
Chris@843 388 cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No output URI available for transform output id \"" << transform.getOutput() << "\", writing a synthetic output resource" << endl;
Chris@494 389 }
Chris@494 390
Chris@494 391 if (transform.getStepSize() != 0) {
Chris@494 392 s << " vamp:step_size \"" << transform.getStepSize() << "\"^^xsd:int ; " << endl;
Chris@494 393 }
Chris@494 394 if (transform.getBlockSize() != 0) {
Chris@494 395 s << " vamp:block_size \"" << transform.getBlockSize() << "\"^^xsd:int ; " << endl;
Chris@494 396 }
Chris@494 397 if (transform.getStartTime() != RealTime::zeroTime) {
Chris@494 398 s << " vamp:start \"" << transform.getStartTime().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
Chris@494 399 }
Chris@494 400 if (transform.getDuration() != RealTime::zeroTime) {
Chris@494 401 s << " vamp:duration \"" << transform.getDuration().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
Chris@494 402 }
Chris@494 403 if (transform.getSampleRate() != 0) {
Chris@494 404 s << " vamp:sample_rate \"" << transform.getSampleRate() << "\"^^xsd:float ; " << endl;
Chris@494 405 }
Chris@494 406
Chris@494 407 QString program = transform.getProgram();
Chris@494 408 if (program != "") {
Chris@494 409 s << " vamp:program \"\"\"" << program << "\"\"\" ;" << endl;
Chris@494 410 }
Chris@494 411
Chris@508 412 QString summary = transform.summaryTypeToString(transform.getSummaryType());
Chris@508 413 if (summary != "") {
Chris@508 414 s << " vamp:summary_type \"" << summary << "\" ;" << endl;
Chris@508 415 }
Chris@508 416
Chris@494 417 Transform::ParameterMap parameters = transform.getParameters();
Chris@494 418 for (Transform::ParameterMap::const_iterator i = parameters.begin();
Chris@494 419 i != parameters.end(); ++i) {
Chris@494 420 QString name = i->first;
Chris@494 421 float value = i->second;
Chris@494 422 s << " vamp:parameter_binding [" << endl;
Chris@494 423 s << " vamp:parameter [ vamp:identifier \"" << name << "\" ] ;" << endl;
Chris@494 424 s << " vamp:value \"" << value << "\"^^xsd:float ;" << endl;
Chris@494 425 s << " ] ;" << endl;
Chris@494 426 }
Chris@494 427
Chris@494 428 if (outputUri != "") {
Chris@592 429 s << " vamp:output <" << QUrl(outputUri).toEncoded().data() << "> ." << endl;
Chris@503 430 } else if (outputId != "") {
Chris@503 431 s << " vamp:output [ vamp:identifier \"" << outputId << "\" ] ." << endl;
Chris@494 432 } else {
Chris@494 433 s << " ." << endl;
Chris@494 434 }
Chris@494 435
Chris@494 436 return str;
Chris@494 437 }
Chris@494 438