annotate rdf/RDFTransformFactory.cpp @ 823:f0558e69a074

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