annotate rdf/RDFImporter.cpp @ 558:1d7ebc05157e

* Some fairly simplistic code to set up layer type properties based on RDF data about feature types (both when running transforms and when importing features from RDF files).
author Chris Cannam
date Thu, 12 Feb 2009 15:26:43 +0000
parents 1ddab154fb9a
children 2e0c987a12bd
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 "RDFImporter.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
Chris@439 26 #include "base/ProgressReporter.h"
Chris@439 27 #include "base/RealTime.h"
Chris@439 28
Chris@439 29 #include "data/model/SparseOneDimensionalModel.h"
Chris@439 30 #include "data/model/SparseTimeValueModel.h"
Chris@439 31 #include "data/model/EditableDenseThreeDimensionalModel.h"
Chris@449 32 #include "data/model/NoteModel.h"
Chris@510 33 #include "data/model/TextModel.h"
Chris@449 34 #include "data/model/RegionModel.h"
Chris@499 35 #include "data/model/WaveFileModel.h"
Chris@499 36
Chris@499 37 #include "data/fileio/FileSource.h"
Chris@520 38 #include "data/fileio/CachedFile.h"
Chris@439 39
Chris@522 40 #ifndef NO_SV_GUI
Chris@522 41 #include "widgets/FileFinder.h"
Chris@522 42 #endif
Chris@522 43
Chris@439 44 using std::cerr;
Chris@439 45 using std::endl;
Chris@439 46
Chris@439 47 class RDFImporterImpl
Chris@439 48 {
Chris@439 49 public:
Chris@439 50 RDFImporterImpl(QString url, int sampleRate);
Chris@439 51 virtual ~RDFImporterImpl();
Chris@490 52
Chris@490 53 void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
Chris@439 54
Chris@439 55 bool isOK();
Chris@439 56 QString getErrorString() const;
Chris@439 57
Chris@439 58 std::vector<Model *> getDataModels(ProgressReporter *);
Chris@439 59
Chris@439 60 protected:
Chris@439 61 QString m_uristring;
Chris@439 62 QString m_errorString;
Chris@499 63 std::map<QString, Model *> m_audioModelMap;
Chris@439 64 int m_sampleRate;
Chris@439 65
Chris@520 66 static bool m_prefixesLoaded;
Chris@520 67 static void loadPrefixes(ProgressReporter *reporter);
Chris@520 68
Chris@499 69 void getDataModelsAudio(std::vector<Model *> &, ProgressReporter *);
Chris@440 70 void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *);
Chris@440 71 void getDataModelsDense(std::vector<Model *> &, ProgressReporter *);
Chris@440 72
Chris@493 73 void getDenseModelTitle(Model *, QString, QString);
Chris@493 74
Chris@440 75 void getDenseFeatureProperties(QString featureUri,
Chris@440 76 int &sampleRate, int &windowLength,
Chris@440 77 int &hopSize, int &width, int &height);
Chris@440 78
Chris@449 79 void fillModel(Model *, long, long, bool, std::vector<float> &, QString);
Chris@439 80 };
Chris@439 81
Chris@520 82 bool RDFImporterImpl::m_prefixesLoaded = false;
Chris@439 83
Chris@439 84 QString
Chris@439 85 RDFImporter::getKnownExtensions()
Chris@439 86 {
Chris@439 87 return "*.rdf *.n3 *.ttl";
Chris@439 88 }
Chris@439 89
Chris@439 90 RDFImporter::RDFImporter(QString url, int sampleRate) :
Chris@439 91 m_d(new RDFImporterImpl(url, sampleRate))
Chris@439 92 {
Chris@439 93 }
Chris@439 94
Chris@439 95 RDFImporter::~RDFImporter()
Chris@439 96 {
Chris@439 97 delete m_d;
Chris@439 98 }
Chris@439 99
Chris@490 100 void
Chris@490 101 RDFImporter::setSampleRate(int sampleRate)
Chris@490 102 {
Chris@490 103 m_d->setSampleRate(sampleRate);
Chris@490 104 }
Chris@490 105
Chris@439 106 bool
Chris@439 107 RDFImporter::isOK()
Chris@439 108 {
Chris@439 109 return m_d->isOK();
Chris@439 110 }
Chris@439 111
Chris@439 112 QString
Chris@439 113 RDFImporter::getErrorString() const
Chris@439 114 {
Chris@439 115 return m_d->getErrorString();
Chris@439 116 }
Chris@439 117
Chris@439 118 std::vector<Model *>
Chris@439 119 RDFImporter::getDataModels(ProgressReporter *r)
Chris@439 120 {
Chris@439 121 return m_d->getDataModels(r);
Chris@439 122 }
Chris@439 123
Chris@439 124 RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) :
Chris@439 125 m_uristring(uri),
Chris@439 126 m_sampleRate(sampleRate)
Chris@439 127 {
Chris@439 128 }
Chris@439 129
Chris@439 130 RDFImporterImpl::~RDFImporterImpl()
Chris@439 131 {
Chris@492 132 SimpleSPARQLQuery::closeSingleSource(m_uristring);
Chris@439 133 }
Chris@439 134
Chris@439 135 bool
Chris@439 136 RDFImporterImpl::isOK()
Chris@439 137 {
Chris@439 138 return (m_errorString == "");
Chris@439 139 }
Chris@439 140
Chris@439 141 QString
Chris@439 142 RDFImporterImpl::getErrorString() const
Chris@439 143 {
Chris@439 144 return m_errorString;
Chris@439 145 }
Chris@439 146
Chris@439 147 std::vector<Model *>
Chris@439 148 RDFImporterImpl::getDataModels(ProgressReporter *reporter)
Chris@439 149 {
Chris@520 150 loadPrefixes(reporter);
Chris@520 151
Chris@439 152 std::vector<Model *> models;
Chris@439 153
Chris@499 154 getDataModelsAudio(models, reporter);
Chris@499 155
Chris@490 156 if (m_sampleRate == 0) {
Chris@490 157 std::cerr << "RDFImporter::getDataModels: invalid sample rate" << std::endl;
Chris@490 158 return models;
Chris@490 159 }
Chris@490 160
Chris@508 161 QString error;
Chris@508 162
Chris@522 163 if (m_errorString != "") {
Chris@522 164 error = m_errorString;
Chris@522 165 }
Chris@508 166 m_errorString = "";
Chris@508 167
Chris@440 168 getDataModelsDense(models, reporter);
Chris@440 169
Chris@522 170 if (m_errorString != "") {
Chris@522 171 error = m_errorString;
Chris@522 172 }
Chris@440 173 m_errorString = "";
Chris@440 174
Chris@440 175 getDataModelsSparse(models, reporter);
Chris@440 176
Chris@522 177 if (m_errorString == "" && error != "") {
Chris@522 178 m_errorString = error;
Chris@522 179 }
Chris@440 180
Chris@440 181 return models;
Chris@440 182 }
Chris@440 183
Chris@440 184 void
Chris@499 185 RDFImporterImpl::getDataModelsAudio(std::vector<Model *> &models,
Chris@499 186 ProgressReporter *reporter)
Chris@499 187 {
Chris@499 188 SimpleSPARQLQuery query = SimpleSPARQLQuery
Chris@499 189 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@499 190 QString
Chris@499 191 (
Chris@499 192 " PREFIX mo: <http://purl.org/ontology/mo/> "
Chris@499 193 " SELECT ?signal ?source FROM <%1> "
Chris@499 194 " WHERE { ?signal a mo:Signal ; mo:available_as ?source } "
Chris@499 195 )
Chris@499 196 .arg(m_uristring));
Chris@499 197
Chris@499 198 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@499 199
Chris@499 200 for (int i = 0; i < results.size(); ++i) {
Chris@499 201
Chris@499 202 QString signal = results[i]["signal"].value;
Chris@499 203 QString source = results[i]["source"].value;
Chris@499 204
Chris@522 205 FileSource *fs = new FileSource(source, reporter);
Chris@522 206 #ifdef NO_SV_GUI
Chris@522 207 if (!fs->isAvailable()) {
Chris@522 208 m_errorString = QString("Signal source \"%1\" is not available").arg(source);
Chris@522 209 delete fs;
Chris@522 210 continue;
Chris@522 211 }
Chris@522 212 #else
Chris@522 213 if (!fs->isAvailable()) {
Chris@522 214 FileFinder *ff = FileFinder::getInstance();
Chris@522 215 QString path = ff->find(FileFinder::AudioFile,
Chris@522 216 fs->getLocation(),
Chris@522 217 m_uristring);
Chris@522 218 if (path != "") {
Chris@522 219 delete fs;
Chris@522 220 fs = new FileSource(path, reporter);
Chris@522 221 if (!fs->isAvailable()) {
Chris@522 222 delete fs;
Chris@522 223 m_errorString = QString("Signal source \"%1\" is not available").arg(source);
Chris@522 224 continue;
Chris@522 225 }
Chris@499 226 }
Chris@522 227 }
Chris@522 228 #endif
Chris@522 229
Chris@522 230 if (reporter) {
Chris@522 231 reporter->setMessage(RDFImporter::tr("Importing audio referenced in RDF..."));
Chris@522 232 }
Chris@522 233 fs->waitForData();
Chris@522 234 WaveFileModel *newModel = new WaveFileModel(*fs, m_sampleRate);
Chris@522 235 if (newModel->isOK()) {
Chris@522 236 std::cerr << "Successfully created wave file model from source at \"" << source.toStdString() << "\"" << std::endl;
Chris@522 237 models.push_back(newModel);
Chris@522 238 m_audioModelMap[signal] = newModel;
Chris@522 239 if (m_sampleRate == 0) {
Chris@522 240 m_sampleRate = newModel->getSampleRate();
Chris@499 241 }
Chris@508 242 } else {
Chris@522 243 m_errorString = QString("Failed to create wave file model from source at \"%1\"").arg(source);
Chris@522 244 delete newModel;
Chris@499 245 }
Chris@522 246 delete fs;
Chris@499 247 }
Chris@499 248 }
Chris@499 249
Chris@499 250 void
Chris@440 251 RDFImporterImpl::getDataModelsDense(std::vector<Model *> &models,
Chris@440 252 ProgressReporter *reporter)
Chris@440 253 {
Chris@499 254 if (reporter) {
Chris@499 255 reporter->setMessage(RDFImporter::tr("Importing dense signal data from RDF..."));
Chris@499 256 }
Chris@499 257
Chris@440 258 SimpleSPARQLQuery query = SimpleSPARQLQuery
Chris@489 259 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@480 260 QString
Chris@440 261 (
Chris@440 262 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 263 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 264
Chris@493 265 " SELECT ?feature ?feature_signal_type ?value "
Chris@440 266 " FROM <%1> "
Chris@440 267
Chris@440 268 " WHERE { "
Chris@440 269
Chris@493 270 " ?signal af:signal_feature ?feature . "
Chris@440 271
Chris@440 272 " ?feature a ?feature_signal_type ; "
Chris@440 273 " af:value ?value . "
Chris@440 274
Chris@440 275 " } "
Chris@440 276 )
Chris@440 277 .arg(m_uristring));
Chris@440 278
Chris@440 279 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@440 280
Chris@440 281 if (!query.isOK()) {
Chris@440 282 m_errorString = query.getErrorString();
Chris@440 283 return;
Chris@440 284 }
Chris@440 285
Chris@440 286 if (query.wasCancelled()) {
Chris@440 287 m_errorString = "Query cancelled";
Chris@440 288 return;
Chris@440 289 }
Chris@440 290
Chris@440 291 for (int i = 0; i < results.size(); ++i) {
Chris@440 292
Chris@440 293 QString feature = results[i]["feature"].value;
Chris@440 294 QString type = results[i]["feature_signal_type"].value;
Chris@440 295 QString value = results[i]["value"].value;
Chris@440 296
Chris@440 297 int sampleRate = 0;
Chris@440 298 int windowLength = 0;
Chris@440 299 int hopSize = 0;
Chris@440 300 int width = 0;
Chris@440 301 int height = 0;
Chris@440 302 getDenseFeatureProperties
Chris@440 303 (feature, sampleRate, windowLength, hopSize, width, height);
Chris@440 304
Chris@440 305 if (sampleRate != 0 && sampleRate != m_sampleRate) {
Chris@440 306 cerr << "WARNING: Sample rate in dense feature description does not match our underlying rate -- using rate from feature description" << endl;
Chris@440 307 }
Chris@440 308 if (sampleRate == 0) sampleRate = m_sampleRate;
Chris@440 309
Chris@440 310 if (hopSize == 0) {
Chris@440 311 cerr << "WARNING: Dense feature description does not specify a hop size -- assuming 1" << endl;
Chris@440 312 hopSize = 1;
Chris@440 313 }
Chris@440 314
Chris@440 315 if (height == 0) {
Chris@440 316 cerr << "WARNING: Dense feature description does not specify feature signal dimensions -- assuming one-dimensional (height = 1)" << endl;
Chris@440 317 height = 1;
Chris@440 318 }
Chris@440 319
Chris@440 320 QStringList values = value.split(' ', QString::SkipEmptyParts);
Chris@440 321
Chris@440 322 if (values.empty()) {
Chris@440 323 cerr << "WARNING: Dense feature description does not specify any values!" << endl;
Chris@440 324 continue;
Chris@440 325 }
Chris@440 326
Chris@440 327 if (height == 1) {
Chris@440 328
Chris@440 329 SparseTimeValueModel *m = new SparseTimeValueModel
Chris@440 330 (sampleRate, hopSize, false);
Chris@440 331
Chris@440 332 for (int j = 0; j < values.size(); ++j) {
Chris@440 333 float f = values[j].toFloat();
Chris@440 334 SparseTimeValueModel::Point point(j * hopSize, f, "");
Chris@440 335 m->addPoint(point);
Chris@440 336 }
Chris@493 337
Chris@493 338 getDenseModelTitle(m, feature, type);
Chris@440 339
Chris@558 340 m->setRDFTypeURI(type);
Chris@558 341
Chris@440 342 models.push_back(m);
Chris@440 343
Chris@440 344 } else {
Chris@440 345
Chris@440 346 EditableDenseThreeDimensionalModel *m =
Chris@535 347 new EditableDenseThreeDimensionalModel
Chris@535 348 (sampleRate, hopSize, height,
Chris@535 349 EditableDenseThreeDimensionalModel::NoCompression, false);
Chris@440 350
Chris@440 351 EditableDenseThreeDimensionalModel::Column column;
Chris@440 352
Chris@440 353 int x = 0;
Chris@440 354
Chris@440 355 for (int j = 0; j < values.size(); ++j) {
Chris@440 356 if (j % height == 0 && !column.empty()) {
Chris@440 357 m->setColumn(x++, column);
Chris@440 358 column.clear();
Chris@440 359 }
Chris@440 360 column.push_back(values[j].toFloat());
Chris@440 361 }
Chris@440 362
Chris@440 363 if (!column.empty()) {
Chris@440 364 m->setColumn(x++, column);
Chris@440 365 }
Chris@440 366
Chris@493 367 getDenseModelTitle(m, feature, type);
Chris@493 368
Chris@558 369 m->setRDFTypeURI(type);
Chris@558 370
Chris@440 371 models.push_back(m);
Chris@440 372 }
Chris@440 373 }
Chris@440 374 }
Chris@440 375
Chris@440 376 void
Chris@493 377 RDFImporterImpl::getDenseModelTitle(Model *m,
Chris@493 378 QString featureUri,
Chris@493 379 QString featureTypeUri)
Chris@493 380 {
Chris@493 381 QString titleQuery = QString
Chris@493 382 (
Chris@493 383 " PREFIX dc: <http://purl.org/dc/elements/1.1/> "
Chris@493 384 " SELECT ?title "
Chris@493 385 " FROM <%1> "
Chris@493 386 " WHERE { "
Chris@493 387 " <%2> dc:title ?title . "
Chris@493 388 " } "
Chris@493 389 ).arg(m_uristring);
Chris@493 390
Chris@493 391 SimpleSPARQLQuery::Value v;
Chris@493 392
Chris@493 393 v = SimpleSPARQLQuery::singleResultQuery
Chris@493 394 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@493 395 titleQuery.arg(featureUri),
Chris@493 396 "title");
Chris@493 397
Chris@493 398 if (v.value != "") {
Chris@493 399 std::cerr << "RDFImporterImpl::getDenseModelTitle: Title (from signal) \"" << v.value.toStdString() << "\"" << std::endl;
Chris@493 400 m->setObjectName(v.value);
Chris@493 401 return;
Chris@493 402 }
Chris@493 403
Chris@493 404 v = SimpleSPARQLQuery::singleResultQuery
Chris@493 405 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@493 406 titleQuery.arg(featureTypeUri),
Chris@493 407 "title");
Chris@493 408
Chris@493 409 if (v.value != "") {
Chris@493 410 std::cerr << "RDFImporterImpl::getDenseModelTitle: Title (from signal type) \"" << v.value.toStdString() << "\"" << std::endl;
Chris@493 411 m->setObjectName(v.value);
Chris@493 412 return;
Chris@493 413 }
Chris@493 414
Chris@493 415 std::cerr << "RDFImporterImpl::getDenseModelTitle: No title available for feature <" << featureUri.toStdString() << ">" << std::endl;
Chris@493 416 }
Chris@493 417
Chris@493 418 void
Chris@440 419 RDFImporterImpl::getDenseFeatureProperties(QString featureUri,
Chris@440 420 int &sampleRate, int &windowLength,
Chris@440 421 int &hopSize, int &width, int &height)
Chris@440 422 {
Chris@489 423 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource;
Chris@489 424
Chris@440 425 QString dimensionsQuery
Chris@440 426 (
Chris@440 427 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 428 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 429
Chris@440 430 " SELECT ?dimensions "
Chris@440 431 " FROM <%1> "
Chris@440 432
Chris@440 433 " WHERE { "
Chris@440 434
Chris@440 435 " <%2> af:dimensions ?dimensions . "
Chris@440 436
Chris@440 437 " } "
Chris@440 438 );
Chris@440 439
Chris@440 440 SimpleSPARQLQuery::Value dimensionsValue =
Chris@489 441 SimpleSPARQLQuery::singleResultQuery
Chris@489 442 (s, dimensionsQuery.arg(m_uristring).arg(featureUri), "dimensions");
Chris@440 443
Chris@440 444 cerr << "Dimensions = \"" << dimensionsValue.value.toStdString() << "\""
Chris@440 445 << endl;
Chris@440 446
Chris@440 447 if (dimensionsValue.value != "") {
Chris@440 448 QStringList dl = dimensionsValue.value.split(" ");
Chris@440 449 if (dl.empty()) dl.push_back(dimensionsValue.value);
Chris@440 450 if (dl.size() > 0) height = dl[0].toInt();
Chris@440 451 if (dl.size() > 1) width = dl[1].toInt();
Chris@440 452 }
Chris@440 453
Chris@440 454 QString queryTemplate
Chris@440 455 (
Chris@440 456 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 457 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 458 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>"
Chris@440 459
Chris@440 460 " SELECT ?%3 "
Chris@440 461 " FROM <%1> "
Chris@440 462
Chris@440 463 " WHERE { "
Chris@440 464
Chris@440 465 " <%2> mo:time ?time . "
Chris@440 466
Chris@440 467 " ?time a tl:Interval ; "
Chris@440 468 " tl:onTimeLine ?timeline . "
Chris@440 469
Chris@440 470 " ?map tl:rangeTimeLine ?timeline . "
Chris@440 471
Chris@440 472 " ?map tl:%3 ?%3 . "
Chris@440 473
Chris@440 474 " } "
Chris@440 475 );
Chris@440 476
Chris@440 477 // Another laborious workaround for rasqal's failure to handle
Chris@440 478 // multiple optionals properly
Chris@440 479
Chris@440 480 SimpleSPARQLQuery::Value srValue =
Chris@489 481 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 482 queryTemplate
Chris@440 483 .arg(m_uristring).arg(featureUri)
Chris@440 484 .arg("sampleRate"),
Chris@440 485 "sampleRate");
Chris@440 486 if (srValue.value != "") {
Chris@440 487 sampleRate = srValue.value.toInt();
Chris@440 488 }
Chris@440 489
Chris@440 490 SimpleSPARQLQuery::Value hopValue =
Chris@489 491 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 492 queryTemplate
Chris@440 493 .arg(m_uristring).arg(featureUri)
Chris@440 494 .arg("hopSize"),
Chris@440 495 "hopSize");
Chris@440 496 if (srValue.value != "") {
Chris@440 497 hopSize = hopValue.value.toInt();
Chris@440 498 }
Chris@440 499
Chris@440 500 SimpleSPARQLQuery::Value winValue =
Chris@489 501 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 502 queryTemplate
Chris@440 503 .arg(m_uristring).arg(featureUri)
Chris@440 504 .arg("windowLength"),
Chris@440 505 "windowLength");
Chris@440 506 if (winValue.value != "") {
Chris@440 507 windowLength = winValue.value.toInt();
Chris@440 508 }
Chris@440 509
Chris@440 510 cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl;
Chris@440 511 }
Chris@440 512
Chris@440 513 void
Chris@440 514 RDFImporterImpl::getDataModelsSparse(std::vector<Model *> &models,
Chris@440 515 ProgressReporter *reporter)
Chris@440 516 {
Chris@499 517 if (reporter) {
Chris@499 518 reporter->setMessage(RDFImporter::tr("Importing event data from RDF..."));
Chris@499 519 }
Chris@499 520
Chris@489 521 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource;
Chris@489 522
Chris@439 523 // Our query is intended to retrieve every thing that has a time,
Chris@439 524 // and every feature type and value associated with a thing that
Chris@439 525 // has a time.
Chris@439 526
Chris@439 527 // We will then need to refine this big bag of results into a set
Chris@439 528 // of data models.
Chris@439 529
Chris@439 530 // Results that have different source signals should go into
Chris@439 531 // different models.
Chris@439 532
Chris@439 533 // Results that have different feature types should go into
Chris@439 534 // different models.
Chris@439 535
Chris@439 536 // Results that are sparse should go into different models from
Chris@439 537 // those that are dense (we need to examine the timestamps to
Chris@439 538 // establish this -- if the timestamps are regular, the results
Chris@439 539 // are dense -- so we can't do it as we go along, only after
Chris@439 540 // collecting all results).
Chris@439 541
Chris@439 542 // Timed things that have features associated with them should not
Chris@439 543 // appear directly in any model -- their features should appear
Chris@439 544 // instead -- and these should be different models from those used
Chris@439 545 // for timed things that do not have features.
Chris@439 546
Chris@439 547 // As we load the results, we'll push them into a partially
Chris@439 548 // structured container that maps from source signal (URI as
Chris@439 549 // string) -> feature type (likewise) -> time -> list of values.
Chris@439 550 // If the source signal or feature type is unavailable, the empty
Chris@439 551 // string will do.
Chris@439 552
Chris@449 553 QString prefixes = QString(
Chris@439 554 " PREFIX event: <http://purl.org/NET/c4dm/event.owl#>"
Chris@449 555 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>"
Chris@439 556 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@439 557 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@449 558 " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
Chris@449 559 );
Chris@439 560
Chris@449 561 QString queryString = prefixes + QString(
Chris@449 562
Chris@499 563 " SELECT ?signal ?timed_thing ?event_type ?value"
Chris@439 564 " FROM <%1>"
Chris@439 565
Chris@439 566 " WHERE {"
Chris@440 567
Chris@440 568 " ?signal a mo:Signal ."
Chris@440 569
Chris@439 570 " ?signal mo:time ?interval ."
Chris@449 571 " ?interval tl:onTimeLine ?tl ."
Chris@449 572 " ?time tl:onTimeLine ?tl ."
Chris@449 573 " ?timed_thing event:time ?time ."
Chris@440 574 " ?timed_thing a ?event_type ."
Chris@440 575
Chris@439 576 " OPTIONAL {"
Chris@440 577 " ?timed_thing af:feature ?value"
Chris@439 578 " }"
Chris@439 579 " }"
Chris@439 580
Chris@439 581 ).arg(m_uristring);
Chris@439 582
Chris@449 583 QString timeQueryString = prefixes + QString(
Chris@449 584
Chris@449 585 " SELECT ?time FROM <%1> "
Chris@449 586 " WHERE { "
Chris@449 587 " <%2> event:time ?t . "
Chris@449 588 " ?t tl:at ?time . "
Chris@449 589 " } "
Chris@449 590
Chris@449 591 ).arg(m_uristring);
Chris@449 592
Chris@449 593 QString rangeQueryString = prefixes + QString(
Chris@449 594
Chris@449 595 " SELECT ?time ?duration FROM <%1> "
Chris@449 596 " WHERE { "
Chris@449 597 " <%2> event:time ?t . "
Chris@449 598 " ?t tl:beginsAt ?time . "
Chris@449 599 " ?t tl:duration ?duration . "
Chris@449 600 " } "
Chris@449 601
Chris@449 602 ).arg(m_uristring);
Chris@449 603
Chris@449 604 QString labelQueryString = prefixes + QString(
Chris@449 605
Chris@449 606 " SELECT ?label FROM <%1> "
Chris@449 607 " WHERE { "
Chris@449 608 " <%2> rdfs:label ?label . "
Chris@449 609 " } "
Chris@449 610
Chris@449 611 ).arg(m_uristring);
Chris@449 612
Chris@510 613 QString textQueryString = prefixes + QString(
Chris@510 614
Chris@510 615 " SELECT ?label FROM <%1> "
Chris@510 616 " WHERE { "
Chris@510 617 " <%2> af:text ?label . "
Chris@510 618 " } "
Chris@510 619
Chris@510 620 ).arg(m_uristring);
Chris@510 621
Chris@489 622 SimpleSPARQLQuery query(s, queryString);
Chris@439 623 query.setProgressReporter(reporter);
Chris@439 624
Chris@500 625 // cerr << "Query will be: " << queryString.toStdString() << endl;
Chris@439 626
Chris@439 627 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@439 628
Chris@439 629 if (!query.isOK()) {
Chris@439 630 m_errorString = query.getErrorString();
Chris@440 631 return;
Chris@439 632 }
Chris@439 633
Chris@439 634 if (query.wasCancelled()) {
Chris@439 635 m_errorString = "Query cancelled";
Chris@440 636 return;
Chris@439 637 }
Chris@439 638
Chris@449 639 /*
Chris@449 640 This function is now only used for sparse data (for dense data
Chris@449 641 we would be in getDataModelsDense instead).
Chris@449 642
Chris@449 643 For sparse data, the determining factors in deciding what model
Chris@449 644 to use are: Do the features have values? and Do the features
Chris@449 645 have duration?
Chris@449 646
Chris@449 647 We can run through the results and check off whether we find
Chris@449 648 values and duration for each of the source+type keys, and then
Chris@449 649 run through the source+type keys pushing each of the results
Chris@449 650 into a suitable model.
Chris@449 651
Chris@449 652 Unfortunately, at this point we do not yet have any actual
Chris@449 653 timing data (time/duration) -- just the time URI.
Chris@449 654
Chris@449 655 What we _could_ do is to create one of each type of model at the
Chris@449 656 start, for each of the source+type keys, and then push each
Chris@449 657 feature into the relevant model depending on what we find out
Chris@449 658 about it. Then return only non-empty models.
Chris@449 659 */
Chris@449 660
Chris@449 661 // Map from signal source to event type to dimensionality to
Chris@449 662 // presence of duration to model ptr. Whee!
Chris@449 663 std::map<QString, std::map<QString, std::map<int, std::map<bool, Model *> > > >
Chris@449 664 modelMap;
Chris@449 665
Chris@439 666 for (int i = 0; i < results.size(); ++i) {
Chris@439 667
Chris@499 668 if (i % 4 == 0) {
Chris@499 669 if (reporter) reporter->setProgress(i/4);
Chris@499 670 }
Chris@499 671
Chris@499 672 QString source = results[i]["signal"].value;
Chris@449 673 QString type = results[i]["event_type"].value;
Chris@449 674 QString thinguri = results[i]["timed_thing"].value;
Chris@449 675
Chris@449 676 RealTime time;
Chris@449 677 RealTime duration;
Chris@439 678
Chris@449 679 bool haveTime = false;
Chris@449 680 bool haveDuration = false;
Chris@439 681
Chris@510 682 QString label = "";
Chris@510 683 bool text = (type.contains("Text") || type.contains("text")); // Ha, ha
Chris@510 684
Chris@510 685 if (text) {
Chris@510 686 label = SimpleSPARQLQuery::singleResultQuery
Chris@510 687 (s, textQueryString.arg(thinguri), "label").value;
Chris@510 688 }
Chris@510 689
Chris@510 690 if (label == "") {
Chris@510 691 label = SimpleSPARQLQuery::singleResultQuery
Chris@510 692 (s, labelQueryString.arg(thinguri), "label").value;
Chris@510 693 }
Chris@449 694
Chris@489 695 SimpleSPARQLQuery rangeQuery(s, rangeQueryString.arg(thinguri));
Chris@450 696 SimpleSPARQLQuery::ResultList rangeResults = rangeQuery.execute();
Chris@450 697 if (!rangeResults.empty()) {
Chris@450 698 // std::cerr << rangeResults.size() << " range results" << std::endl;
Chris@450 699 time = RealTime::fromXsdDuration
Chris@450 700 (rangeResults[0]["time"].value.toStdString());
Chris@450 701 duration = RealTime::fromXsdDuration
Chris@450 702 (rangeResults[0]["duration"].value.toStdString());
Chris@450 703 // std::cerr << "duration string " << rangeResults[0]["duration"].value.toStdString() << std::endl;
Chris@449 704 haveTime = true;
Chris@450 705 haveDuration = true;
Chris@449 706 } else {
Chris@450 707 QString timestring = SimpleSPARQLQuery::singleResultQuery
Chris@489 708 (s, timeQueryString.arg(thinguri), "time").value;
Chris@520 709 // std::cerr << "timestring = " << timestring.toStdString() << std::endl;
Chris@450 710 if (timestring != "") {
Chris@450 711 time = RealTime::fromXsdDuration(timestring.toStdString());
Chris@449 712 haveTime = true;
Chris@449 713 }
Chris@449 714 }
Chris@439 715
Chris@439 716 QString valuestring = results[i]["value"].value;
Chris@449 717 std::vector<float> values;
Chris@449 718
Chris@439 719 if (valuestring != "") {
Chris@449 720 QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts);
Chris@449 721 for (int j = 0; j < vsl.size(); ++j) {
Chris@449 722 bool success = false;
Chris@449 723 float v = vsl[j].toFloat(&success);
Chris@449 724 if (success) values.push_back(v);
Chris@449 725 }
Chris@439 726 }
Chris@439 727
Chris@449 728 int dimensions = 1;
Chris@449 729 if (values.size() == 1) dimensions = 2;
Chris@449 730 else if (values.size() > 1) dimensions = 3;
Chris@449 731
Chris@449 732 Model *model = 0;
Chris@449 733
Chris@449 734 if (modelMap[source][type][dimensions].find(haveDuration) ==
Chris@449 735 modelMap[source][type][dimensions].end()) {
Chris@449 736
Chris@449 737 /*
Chris@449 738 std::cerr << "Creating new model: source = " << source.toStdString()
Chris@449 739 << ", type = " << type.toStdString() << ", dimensions = "
Chris@449 740 << dimensions << ", haveDuration = " << haveDuration
Chris@449 741 << ", time = " << time << ", duration = " << duration
Chris@449 742 << std::endl;
Chris@449 743 */
Chris@449 744
Chris@449 745 if (!haveDuration) {
Chris@449 746
Chris@449 747 if (dimensions == 1) {
Chris@449 748
Chris@510 749 if (text) {
Chris@510 750
Chris@510 751 model = new TextModel(m_sampleRate, 1, false);
Chris@510 752
Chris@510 753 } else {
Chris@510 754
Chris@510 755 model = new SparseOneDimensionalModel(m_sampleRate, 1, false);
Chris@510 756 }
Chris@449 757
Chris@449 758 } else if (dimensions == 2) {
Chris@449 759
Chris@510 760 if (text) {
Chris@510 761
Chris@510 762 model = new TextModel(m_sampleRate, 1, false);
Chris@510 763
Chris@510 764 } else {
Chris@510 765
Chris@510 766 model = new SparseTimeValueModel(m_sampleRate, 1, false);
Chris@510 767 }
Chris@449 768
Chris@449 769 } else {
Chris@449 770
Chris@449 771 // We don't have a three-dimensional sparse model,
Chris@449 772 // so use a note model. We do have some logic (in
Chris@449 773 // extractStructure below) for guessing whether
Chris@449 774 // this should after all have been a dense model,
Chris@449 775 // but it's hard to apply it because we don't have
Chris@449 776 // all the necessary timing data yet... hmm
Chris@449 777
Chris@449 778 model = new NoteModel(m_sampleRate, 1, false);
Chris@449 779 }
Chris@449 780
Chris@449 781 } else { // haveDuration
Chris@449 782
Chris@449 783 if (dimensions == 1 || dimensions == 2) {
Chris@449 784
Chris@449 785 // If our units are frequency or midi pitch, we
Chris@449 786 // should be using a note model... hm
Chris@449 787
Chris@449 788 model = new RegionModel(m_sampleRate, 1, false);
Chris@449 789
Chris@449 790 } else {
Chris@449 791
Chris@449 792 // We don't have a three-dimensional sparse model,
Chris@449 793 // so use a note model. We do have some logic (in
Chris@449 794 // extractStructure below) for guessing whether
Chris@449 795 // this should after all have been a dense model,
Chris@449 796 // but it's hard to apply it because we don't have
Chris@449 797 // all the necessary timing data yet... hmm
Chris@449 798
Chris@449 799 model = new NoteModel(m_sampleRate, 1, false);
Chris@449 800 }
Chris@449 801 }
Chris@449 802
Chris@558 803 model->setRDFTypeURI(type);
Chris@558 804
Chris@499 805 if (m_audioModelMap.find(source) != m_audioModelMap.end()) {
Chris@499 806 std::cerr << "source model for " << model << " is " << m_audioModelMap[source] << std::endl;
Chris@499 807 model->setSourceModel(m_audioModelMap[source]);
Chris@499 808 }
Chris@499 809
Chris@493 810 QString titleQuery = QString
Chris@493 811 (
Chris@493 812 " PREFIX dc: <http://purl.org/dc/elements/1.1/> "
Chris@493 813 " SELECT ?title "
Chris@493 814 " FROM <%1> "
Chris@493 815 " WHERE { "
Chris@493 816 " <%2> dc:title ?title . "
Chris@493 817 " } "
Chris@493 818 ).arg(m_uristring).arg(type);
Chris@493 819 QString title = SimpleSPARQLQuery::singleResultQuery
Chris@493 820 (s, titleQuery, "title").value;
Chris@493 821 if (title != "") model->setObjectName(title);
Chris@493 822
Chris@449 823 modelMap[source][type][dimensions][haveDuration] = model;
Chris@449 824 models.push_back(model);
Chris@449 825 }
Chris@449 826
Chris@449 827 model = modelMap[source][type][dimensions][haveDuration];
Chris@449 828
Chris@449 829 if (model) {
Chris@449 830 long ftime = RealTime::realTime2Frame(time, m_sampleRate);
Chris@449 831 long fduration = RealTime::realTime2Frame(duration, m_sampleRate);
Chris@449 832 fillModel(model, ftime, fduration, haveDuration, values, label);
Chris@439 833 }
Chris@439 834 }
Chris@439 835 }
Chris@439 836
Chris@439 837 void
Chris@449 838 RDFImporterImpl::fillModel(Model *model,
Chris@449 839 long ftime,
Chris@449 840 long fduration,
Chris@449 841 bool haveDuration,
Chris@449 842 std::vector<float> &values,
Chris@449 843 QString label)
Chris@449 844 {
Chris@493 845 // std::cerr << "RDFImporterImpl::fillModel: adding point at frame " << ftime << std::endl;
Chris@492 846
Chris@449 847 SparseOneDimensionalModel *sodm =
Chris@449 848 dynamic_cast<SparseOneDimensionalModel *>(model);
Chris@449 849 if (sodm) {
Chris@449 850 SparseOneDimensionalModel::Point point(ftime, label);
Chris@449 851 sodm->addPoint(point);
Chris@449 852 return;
Chris@449 853 }
Chris@449 854
Chris@510 855 TextModel *tm =
Chris@510 856 dynamic_cast<TextModel *>(model);
Chris@510 857 if (tm) {
Chris@510 858 TextModel::Point point
Chris@510 859 (ftime,
Chris@510 860 values.empty() ? 0.5f : values[0] < 0.f ? 0.f : values[0] > 1.f ? 1.f : values[0], // I was young and feckless once too
Chris@510 861 label);
Chris@510 862 tm->addPoint(point);
Chris@510 863 return;
Chris@510 864 }
Chris@510 865
Chris@449 866 SparseTimeValueModel *stvm =
Chris@449 867 dynamic_cast<SparseTimeValueModel *>(model);
Chris@449 868 if (stvm) {
Chris@449 869 SparseTimeValueModel::Point point
Chris@449 870 (ftime, values.empty() ? 0.f : values[0], label);
Chris@449 871 stvm->addPoint(point);
Chris@449 872 return;
Chris@449 873 }
Chris@449 874
Chris@449 875 NoteModel *nm =
Chris@449 876 dynamic_cast<NoteModel *>(model);
Chris@449 877 if (nm) {
Chris@449 878 if (haveDuration) {
Chris@449 879 float value = 0.f, level = 1.f;
Chris@449 880 if (!values.empty()) {
Chris@449 881 value = values[0];
Chris@449 882 if (values.size() > 1) {
Chris@449 883 level = values[1];
Chris@449 884 }
Chris@449 885 }
Chris@449 886 NoteModel::Point point(ftime, value, fduration, level, label);
Chris@449 887 nm->addPoint(point);
Chris@449 888 } else {
Chris@449 889 float value = 0.f, duration = 1.f, level = 1.f;
Chris@449 890 if (!values.empty()) {
Chris@449 891 value = values[0];
Chris@449 892 if (values.size() > 1) {
Chris@449 893 duration = values[1];
Chris@449 894 if (values.size() > 2) {
Chris@449 895 level = values[2];
Chris@449 896 }
Chris@449 897 }
Chris@449 898 }
Chris@449 899 NoteModel::Point point(ftime, value, duration, level, label);
Chris@449 900 nm->addPoint(point);
Chris@449 901 }
Chris@449 902 return;
Chris@449 903 }
Chris@449 904
Chris@449 905 RegionModel *rm =
Chris@449 906 dynamic_cast<RegionModel *>(model);
Chris@449 907 if (rm) {
Chris@449 908 if (haveDuration) {
Chris@449 909 RegionModel::Point point
Chris@449 910 (ftime, values.empty() ? 0.f : values[0], fduration, label);
Chris@449 911 rm->addPoint(point);
Chris@449 912 } else {
Chris@449 913 // This won't actually happen -- we only create region models
Chris@449 914 // if we do have duration -- but just for completeness
Chris@449 915 float value = 0.f, duration = 1.f;
Chris@449 916 if (!values.empty()) {
Chris@449 917 value = values[0];
Chris@449 918 if (values.size() > 1) {
Chris@449 919 duration = values[1];
Chris@449 920 }
Chris@449 921 }
Chris@449 922 RegionModel::Point point(ftime, value, duration, label);
Chris@449 923 rm->addPoint(point);
Chris@449 924 }
Chris@449 925 return;
Chris@449 926 }
Chris@449 927
Chris@449 928 std::cerr << "WARNING: RDFImporterImpl::fillModel: Unknown or unexpected model type" << std::endl;
Chris@449 929 return;
Chris@449 930 }
Chris@449 931
Chris@490 932 RDFImporter::RDFDocumentType
Chris@490 933 RDFImporter::identifyDocumentType(QString url)
Chris@490 934 {
Chris@490 935 bool haveAudio = false;
Chris@490 936 bool haveAnnotations = false;
Chris@449 937
Chris@499 938 // This query is not expected to return any values, but if it
Chris@499 939 // executes successfully (leaving no error in the error string)
Chris@499 940 // then we know we have RDF
Chris@499 941 SimpleSPARQLQuery q(SimpleSPARQLQuery::QueryFromSingleSource,
Chris@499 942 QString(" SELECT ?x FROM <%1> WHERE { ?x <y> <z> } ")
Chris@499 943 .arg(url));
Chris@499 944
Chris@499 945 SimpleSPARQLQuery::ResultList r = q.execute();
Chris@499 946 if (!q.isOK()) {
Chris@542 947 SimpleSPARQLQuery::closeSingleSource(url);
Chris@499 948 return NotRDF;
Chris@499 949 }
Chris@499 950
Chris@490 951 SimpleSPARQLQuery::Value value =
Chris@490 952 SimpleSPARQLQuery::singleResultQuery
Chris@490 953 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 954 QString
Chris@490 955 (" PREFIX mo: <http://purl.org/ontology/mo/> "
Chris@490 956 " SELECT ?url FROM <%1> "
Chris@490 957 " WHERE { ?signal a mo:Signal ; mo:available_as ?url } "
Chris@490 958 ).arg(url),
Chris@490 959 "url");
Chris@490 960
Chris@490 961 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 962 haveAudio = true;
Chris@490 963 }
Chris@490 964
Chris@490 965 value =
Chris@490 966 SimpleSPARQLQuery::singleResultQuery
Chris@490 967 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 968 QString
Chris@490 969 (" PREFIX event: <http://purl.org/NET/c4dm/event.owl#> "
Chris@490 970 " SELECT ?thing FROM <%1> "
Chris@490 971 " WHERE { ?thing event:time ?time } "
Chris@490 972 ).arg(url),
Chris@490 973 "thing");
Chris@490 974
Chris@490 975 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 976 haveAnnotations = true;
Chris@490 977 }
Chris@490 978
Chris@490 979 if (!haveAnnotations) {
Chris@490 980
Chris@490 981 value =
Chris@490 982 SimpleSPARQLQuery::singleResultQuery
Chris@490 983 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 984 QString
Chris@490 985 (" PREFIX af: <http://purl.org/ontology/af/> "
Chris@490 986 " SELECT ?thing FROM <%1> "
Chris@490 987 " WHERE { ?signal af:signal_feature ?thing } "
Chris@490 988 ).arg(url),
Chris@490 989 "thing");
Chris@490 990
Chris@490 991 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 992 haveAnnotations = true;
Chris@490 993 }
Chris@490 994 }
Chris@490 995
Chris@542 996 SimpleSPARQLQuery::closeSingleSource(url);
Chris@542 997
Chris@490 998 if (haveAudio) {
Chris@490 999 if (haveAnnotations) {
Chris@490 1000 return AudioRefAndAnnotations;
Chris@490 1001 } else {
Chris@490 1002 return AudioRef;
Chris@490 1003 }
Chris@490 1004 } else {
Chris@490 1005 if (haveAnnotations) {
Chris@490 1006 return Annotations;
Chris@490 1007 } else {
Chris@499 1008 return OtherRDFDocument;
Chris@490 1009 }
Chris@490 1010 }
Chris@492 1011
Chris@542 1012 return OtherRDFDocument;
Chris@490 1013 }
Chris@490 1014
Chris@520 1015 void
Chris@520 1016 RDFImporterImpl::loadPrefixes(ProgressReporter *reporter)
Chris@520 1017 {
Chris@520 1018 return;
Chris@520 1019 //!!!
Chris@520 1020 if (m_prefixesLoaded) return;
Chris@520 1021 const char *prefixes[] = {
Chris@520 1022 "http://purl.org/NET/c4dm/event.owl",
Chris@520 1023 "http://purl.org/NET/c4dm/timeline.owl",
Chris@520 1024 "http://purl.org/ontology/mo/",
Chris@520 1025 "http://purl.org/ontology/af/",
Chris@520 1026 "http://www.w3.org/2000/01/rdf-schema",
Chris@520 1027 "http://purl.org/dc/elements/1.1/",
Chris@520 1028 };
Chris@520 1029 for (size_t i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); ++i) {
Chris@520 1030 CachedFile cf(prefixes[i], reporter, "application/rdf+xml");
Chris@520 1031 if (!cf.isOK()) continue;
Chris@520 1032 SimpleSPARQLQuery::addSourceToModel
Chris@520 1033 (QUrl::fromLocalFile(cf.getLocalFilename()).toString());
Chris@520 1034 }
Chris@520 1035 m_prefixesLoaded = true;
Chris@520 1036 }