annotate rdf/RDFImporter.cpp @ 492:23945cdd7161

* Update RDF query stuff again so as to set up a temporary datastore each time we want to query over an rdf file, instead of using rasqal against the file. Seems the only way to avoid threading and storage management issues when trying to load from a single-source file and perform queries against our main datastore at the same time. Maybe.
author Chris Cannam
date Mon, 24 Nov 2008 16:26:11 +0000
parents c3fb8258e34d
children 3931711b5671
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@449 33 #include "data/model/RegionModel.h"
Chris@439 34
Chris@439 35 using std::cerr;
Chris@439 36 using std::endl;
Chris@439 37
Chris@439 38 class RDFImporterImpl
Chris@439 39 {
Chris@439 40 public:
Chris@439 41 RDFImporterImpl(QString url, int sampleRate);
Chris@439 42 virtual ~RDFImporterImpl();
Chris@490 43
Chris@490 44 void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
Chris@439 45
Chris@439 46 bool isOK();
Chris@439 47 QString getErrorString() const;
Chris@439 48
Chris@490 49 QString getAudioAvailableUrl() const { return m_audioAvailableAt; }
Chris@490 50
Chris@439 51 std::vector<Model *> getDataModels(ProgressReporter *);
Chris@439 52
Chris@439 53 protected:
Chris@439 54 QString m_uristring;
Chris@439 55 QString m_errorString;
Chris@490 56 QString m_audioAvailableAt;
Chris@439 57 int m_sampleRate;
Chris@439 58
Chris@440 59 void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *);
Chris@440 60 void getDataModelsDense(std::vector<Model *> &, ProgressReporter *);
Chris@440 61
Chris@440 62 void getDenseFeatureProperties(QString featureUri,
Chris@440 63 int &sampleRate, int &windowLength,
Chris@440 64 int &hopSize, int &width, int &height);
Chris@440 65
Chris@449 66
Chris@449 67 void fillModel(Model *, long, long, bool, std::vector<float> &, QString);
Chris@439 68 };
Chris@439 69
Chris@439 70
Chris@439 71 QString
Chris@439 72 RDFImporter::getKnownExtensions()
Chris@439 73 {
Chris@439 74 return "*.rdf *.n3 *.ttl";
Chris@439 75 }
Chris@439 76
Chris@439 77 RDFImporter::RDFImporter(QString url, int sampleRate) :
Chris@439 78 m_d(new RDFImporterImpl(url, sampleRate))
Chris@439 79 {
Chris@439 80 }
Chris@439 81
Chris@439 82 RDFImporter::~RDFImporter()
Chris@439 83 {
Chris@439 84 delete m_d;
Chris@439 85 }
Chris@439 86
Chris@490 87 void
Chris@490 88 RDFImporter::setSampleRate(int sampleRate)
Chris@490 89 {
Chris@490 90 m_d->setSampleRate(sampleRate);
Chris@490 91 }
Chris@490 92
Chris@439 93 bool
Chris@439 94 RDFImporter::isOK()
Chris@439 95 {
Chris@439 96 return m_d->isOK();
Chris@439 97 }
Chris@439 98
Chris@439 99 QString
Chris@439 100 RDFImporter::getErrorString() const
Chris@439 101 {
Chris@439 102 return m_d->getErrorString();
Chris@439 103 }
Chris@439 104
Chris@490 105 QString
Chris@490 106 RDFImporter::getAudioAvailableUrl() const
Chris@490 107 {
Chris@490 108 return m_d->getAudioAvailableUrl();
Chris@490 109 }
Chris@490 110
Chris@439 111 std::vector<Model *>
Chris@439 112 RDFImporter::getDataModels(ProgressReporter *r)
Chris@439 113 {
Chris@439 114 return m_d->getDataModels(r);
Chris@439 115 }
Chris@439 116
Chris@439 117 RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) :
Chris@439 118 m_uristring(uri),
Chris@439 119 m_sampleRate(sampleRate)
Chris@439 120 {
Chris@490 121 SimpleSPARQLQuery::Value value =
Chris@490 122 SimpleSPARQLQuery::singleResultQuery
Chris@490 123 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 124 QString
Chris@490 125 (" PREFIX mo: <http://purl.org/ontology/mo/> "
Chris@490 126 " SELECT ?url FROM <%1> "
Chris@490 127 " WHERE { ?signal a mo:Signal ; mo:available_as ?url } "
Chris@492 128 ).arg(m_uristring),
Chris@490 129 "url");
Chris@490 130
Chris@490 131 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 132 m_audioAvailableAt = value.value;
Chris@490 133 }
Chris@439 134 }
Chris@439 135
Chris@439 136 RDFImporterImpl::~RDFImporterImpl()
Chris@439 137 {
Chris@492 138 SimpleSPARQLQuery::closeSingleSource(m_uristring);
Chris@439 139 }
Chris@439 140
Chris@439 141 bool
Chris@439 142 RDFImporterImpl::isOK()
Chris@439 143 {
Chris@439 144 return (m_errorString == "");
Chris@439 145 }
Chris@439 146
Chris@439 147 QString
Chris@439 148 RDFImporterImpl::getErrorString() const
Chris@439 149 {
Chris@439 150 return m_errorString;
Chris@439 151 }
Chris@439 152
Chris@439 153 std::vector<Model *>
Chris@439 154 RDFImporterImpl::getDataModels(ProgressReporter *reporter)
Chris@439 155 {
Chris@439 156 std::vector<Model *> models;
Chris@439 157
Chris@490 158 if (m_sampleRate == 0) {
Chris@490 159 std::cerr << "RDFImporter::getDataModels: invalid sample rate" << std::endl;
Chris@490 160 return models;
Chris@490 161 }
Chris@490 162
Chris@440 163 getDataModelsDense(models, reporter);
Chris@440 164
Chris@440 165 QString error;
Chris@440 166 if (!isOK()) error = m_errorString;
Chris@440 167 m_errorString = "";
Chris@440 168
Chris@440 169 getDataModelsSparse(models, reporter);
Chris@440 170
Chris@440 171 if (isOK()) m_errorString = error;
Chris@440 172
Chris@440 173 return models;
Chris@440 174 }
Chris@440 175
Chris@440 176 void
Chris@440 177 RDFImporterImpl::getDataModelsDense(std::vector<Model *> &models,
Chris@440 178 ProgressReporter *reporter)
Chris@440 179 {
Chris@440 180 SimpleSPARQLQuery query = SimpleSPARQLQuery
Chris@489 181 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@480 182 QString
Chris@440 183 (
Chris@440 184 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 185 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 186
Chris@440 187 " SELECT ?feature ?signal_source ?feature_signal_type ?value "
Chris@440 188 " FROM <%1> "
Chris@440 189
Chris@440 190 " WHERE { "
Chris@440 191
Chris@440 192 " ?signal a mo:Signal ; "
Chris@440 193 " mo:available_as ?signal_source ; "
Chris@440 194 " af:signal_feature ?feature . "
Chris@440 195
Chris@440 196 " ?feature a ?feature_signal_type ; "
Chris@440 197 " af:value ?value . "
Chris@440 198
Chris@440 199 " } "
Chris@440 200 )
Chris@440 201 .arg(m_uristring));
Chris@440 202
Chris@440 203 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@440 204
Chris@440 205 if (!query.isOK()) {
Chris@440 206 m_errorString = query.getErrorString();
Chris@440 207 return;
Chris@440 208 }
Chris@440 209
Chris@440 210 if (query.wasCancelled()) {
Chris@440 211 m_errorString = "Query cancelled";
Chris@440 212 return;
Chris@440 213 }
Chris@440 214
Chris@440 215 for (int i = 0; i < results.size(); ++i) {
Chris@440 216
Chris@440 217 QString feature = results[i]["feature"].value;
Chris@440 218 QString source = results[i]["signal_source"].value;
Chris@440 219 QString type = results[i]["feature_signal_type"].value;
Chris@440 220 QString value = results[i]["value"].value;
Chris@440 221
Chris@440 222 int sampleRate = 0;
Chris@440 223 int windowLength = 0;
Chris@440 224 int hopSize = 0;
Chris@440 225 int width = 0;
Chris@440 226 int height = 0;
Chris@440 227 getDenseFeatureProperties
Chris@440 228 (feature, sampleRate, windowLength, hopSize, width, height);
Chris@440 229
Chris@440 230 if (sampleRate != 0 && sampleRate != m_sampleRate) {
Chris@440 231 cerr << "WARNING: Sample rate in dense feature description does not match our underlying rate -- using rate from feature description" << endl;
Chris@440 232 }
Chris@440 233 if (sampleRate == 0) sampleRate = m_sampleRate;
Chris@440 234
Chris@440 235 if (hopSize == 0) {
Chris@440 236 cerr << "WARNING: Dense feature description does not specify a hop size -- assuming 1" << endl;
Chris@440 237 hopSize = 1;
Chris@440 238 }
Chris@440 239
Chris@440 240 if (height == 0) {
Chris@440 241 cerr << "WARNING: Dense feature description does not specify feature signal dimensions -- assuming one-dimensional (height = 1)" << endl;
Chris@440 242 height = 1;
Chris@440 243 }
Chris@440 244
Chris@440 245 QStringList values = value.split(' ', QString::SkipEmptyParts);
Chris@440 246
Chris@440 247 if (values.empty()) {
Chris@440 248 cerr << "WARNING: Dense feature description does not specify any values!" << endl;
Chris@440 249 continue;
Chris@440 250 }
Chris@440 251
Chris@440 252 if (height == 1) {
Chris@440 253
Chris@440 254 SparseTimeValueModel *m = new SparseTimeValueModel
Chris@440 255 (sampleRate, hopSize, false);
Chris@440 256
Chris@440 257 for (int j = 0; j < values.size(); ++j) {
Chris@440 258 float f = values[j].toFloat();
Chris@440 259 SparseTimeValueModel::Point point(j * hopSize, f, "");
Chris@440 260 m->addPoint(point);
Chris@440 261 }
Chris@440 262
Chris@440 263 models.push_back(m);
Chris@440 264
Chris@440 265 } else {
Chris@440 266
Chris@440 267 EditableDenseThreeDimensionalModel *m =
Chris@440 268 new EditableDenseThreeDimensionalModel(sampleRate, hopSize,
Chris@440 269 height, false);
Chris@440 270
Chris@440 271 EditableDenseThreeDimensionalModel::Column column;
Chris@440 272
Chris@440 273 int x = 0;
Chris@440 274
Chris@440 275 for (int j = 0; j < values.size(); ++j) {
Chris@440 276 if (j % height == 0 && !column.empty()) {
Chris@440 277 m->setColumn(x++, column);
Chris@440 278 column.clear();
Chris@440 279 }
Chris@440 280 column.push_back(values[j].toFloat());
Chris@440 281 }
Chris@440 282
Chris@440 283 if (!column.empty()) {
Chris@440 284 m->setColumn(x++, column);
Chris@440 285 }
Chris@440 286
Chris@440 287 models.push_back(m);
Chris@440 288 }
Chris@440 289 }
Chris@440 290 }
Chris@440 291
Chris@440 292 void
Chris@440 293 RDFImporterImpl::getDenseFeatureProperties(QString featureUri,
Chris@440 294 int &sampleRate, int &windowLength,
Chris@440 295 int &hopSize, int &width, int &height)
Chris@440 296 {
Chris@489 297 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource;
Chris@489 298
Chris@440 299 QString dimensionsQuery
Chris@440 300 (
Chris@440 301 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 302 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 303
Chris@440 304 " SELECT ?dimensions "
Chris@440 305 " FROM <%1> "
Chris@440 306
Chris@440 307 " WHERE { "
Chris@440 308
Chris@440 309 " <%2> af:dimensions ?dimensions . "
Chris@440 310
Chris@440 311 " } "
Chris@440 312 );
Chris@440 313
Chris@440 314 SimpleSPARQLQuery::Value dimensionsValue =
Chris@489 315 SimpleSPARQLQuery::singleResultQuery
Chris@489 316 (s, dimensionsQuery.arg(m_uristring).arg(featureUri), "dimensions");
Chris@440 317
Chris@440 318 cerr << "Dimensions = \"" << dimensionsValue.value.toStdString() << "\""
Chris@440 319 << endl;
Chris@440 320
Chris@440 321 if (dimensionsValue.value != "") {
Chris@440 322 QStringList dl = dimensionsValue.value.split(" ");
Chris@440 323 if (dl.empty()) dl.push_back(dimensionsValue.value);
Chris@440 324 if (dl.size() > 0) height = dl[0].toInt();
Chris@440 325 if (dl.size() > 1) width = dl[1].toInt();
Chris@440 326 }
Chris@440 327
Chris@440 328 QString queryTemplate
Chris@440 329 (
Chris@440 330 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@440 331 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@440 332 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>"
Chris@440 333
Chris@440 334 " SELECT ?%3 "
Chris@440 335 " FROM <%1> "
Chris@440 336
Chris@440 337 " WHERE { "
Chris@440 338
Chris@440 339 " <%2> mo:time ?time . "
Chris@440 340
Chris@440 341 " ?time a tl:Interval ; "
Chris@440 342 " tl:onTimeLine ?timeline . "
Chris@440 343
Chris@440 344 " ?map tl:rangeTimeLine ?timeline . "
Chris@440 345
Chris@440 346 " ?map tl:%3 ?%3 . "
Chris@440 347
Chris@440 348 " } "
Chris@440 349 );
Chris@440 350
Chris@440 351 // Another laborious workaround for rasqal's failure to handle
Chris@440 352 // multiple optionals properly
Chris@440 353
Chris@440 354 SimpleSPARQLQuery::Value srValue =
Chris@489 355 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 356 queryTemplate
Chris@440 357 .arg(m_uristring).arg(featureUri)
Chris@440 358 .arg("sampleRate"),
Chris@440 359 "sampleRate");
Chris@440 360 if (srValue.value != "") {
Chris@440 361 sampleRate = srValue.value.toInt();
Chris@440 362 }
Chris@440 363
Chris@440 364 SimpleSPARQLQuery::Value hopValue =
Chris@489 365 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 366 queryTemplate
Chris@440 367 .arg(m_uristring).arg(featureUri)
Chris@440 368 .arg("hopSize"),
Chris@440 369 "hopSize");
Chris@440 370 if (srValue.value != "") {
Chris@440 371 hopSize = hopValue.value.toInt();
Chris@440 372 }
Chris@440 373
Chris@440 374 SimpleSPARQLQuery::Value winValue =
Chris@489 375 SimpleSPARQLQuery::singleResultQuery(s,
Chris@480 376 queryTemplate
Chris@440 377 .arg(m_uristring).arg(featureUri)
Chris@440 378 .arg("windowLength"),
Chris@440 379 "windowLength");
Chris@440 380 if (winValue.value != "") {
Chris@440 381 windowLength = winValue.value.toInt();
Chris@440 382 }
Chris@440 383
Chris@440 384 cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl;
Chris@440 385 }
Chris@440 386
Chris@440 387 void
Chris@440 388 RDFImporterImpl::getDataModelsSparse(std::vector<Model *> &models,
Chris@440 389 ProgressReporter *reporter)
Chris@440 390 {
Chris@489 391 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource;
Chris@489 392
Chris@439 393 // Our query is intended to retrieve every thing that has a time,
Chris@439 394 // and every feature type and value associated with a thing that
Chris@439 395 // has a time.
Chris@439 396
Chris@439 397 // We will then need to refine this big bag of results into a set
Chris@439 398 // of data models.
Chris@439 399
Chris@439 400 // Results that have different source signals should go into
Chris@439 401 // different models.
Chris@439 402
Chris@439 403 // Results that have different feature types should go into
Chris@439 404 // different models.
Chris@439 405
Chris@439 406 // Results that are sparse should go into different models from
Chris@439 407 // those that are dense (we need to examine the timestamps to
Chris@439 408 // establish this -- if the timestamps are regular, the results
Chris@439 409 // are dense -- so we can't do it as we go along, only after
Chris@439 410 // collecting all results).
Chris@439 411
Chris@439 412 // Timed things that have features associated with them should not
Chris@439 413 // appear directly in any model -- their features should appear
Chris@439 414 // instead -- and these should be different models from those used
Chris@439 415 // for timed things that do not have features.
Chris@439 416
Chris@439 417 // As we load the results, we'll push them into a partially
Chris@439 418 // structured container that maps from source signal (URI as
Chris@439 419 // string) -> feature type (likewise) -> time -> list of values.
Chris@439 420 // If the source signal or feature type is unavailable, the empty
Chris@439 421 // string will do.
Chris@439 422
Chris@449 423 QString prefixes = QString(
Chris@439 424 " PREFIX event: <http://purl.org/NET/c4dm/event.owl#>"
Chris@449 425 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>"
Chris@439 426 " PREFIX mo: <http://purl.org/ontology/mo/>"
Chris@439 427 " PREFIX af: <http://purl.org/ontology/af/>"
Chris@449 428 " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
Chris@449 429 );
Chris@439 430
Chris@449 431 QString queryString = prefixes + QString(
Chris@449 432
Chris@449 433 " SELECT ?signal_source ?timed_thing ?event_type ?value"
Chris@439 434 " FROM <%1>"
Chris@439 435
Chris@439 436 " WHERE {"
Chris@440 437
Chris@440 438 " ?signal mo:available_as ?signal_source ."
Chris@440 439 " ?signal a mo:Signal ."
Chris@440 440
Chris@439 441 " ?signal mo:time ?interval ."
Chris@449 442 " ?interval tl:onTimeLine ?tl ."
Chris@449 443 " ?time tl:onTimeLine ?tl ."
Chris@449 444 " ?timed_thing event:time ?time ."
Chris@440 445 " ?timed_thing a ?event_type ."
Chris@440 446
Chris@439 447 " OPTIONAL {"
Chris@440 448 " ?timed_thing af:feature ?value"
Chris@439 449 " }"
Chris@439 450 " }"
Chris@439 451
Chris@439 452 ).arg(m_uristring);
Chris@439 453
Chris@449 454 QString timeQueryString = prefixes + QString(
Chris@449 455
Chris@449 456 " SELECT ?time FROM <%1> "
Chris@449 457 " WHERE { "
Chris@449 458 " <%2> event:time ?t . "
Chris@449 459 " ?t tl:at ?time . "
Chris@449 460 " } "
Chris@449 461
Chris@449 462 ).arg(m_uristring);
Chris@449 463
Chris@449 464 QString rangeQueryString = prefixes + QString(
Chris@449 465
Chris@449 466 " SELECT ?time ?duration FROM <%1> "
Chris@449 467 " WHERE { "
Chris@449 468 " <%2> event:time ?t . "
Chris@449 469 " ?t tl:beginsAt ?time . "
Chris@449 470 " ?t tl:duration ?duration . "
Chris@449 471 " } "
Chris@449 472
Chris@449 473 ).arg(m_uristring);
Chris@449 474
Chris@449 475 QString labelQueryString = prefixes + QString(
Chris@449 476
Chris@449 477 " SELECT ?label FROM <%1> "
Chris@449 478 " WHERE { "
Chris@449 479 " <%2> rdfs:label ?label . "
Chris@449 480 " } "
Chris@449 481
Chris@449 482 ).arg(m_uristring);
Chris@449 483
Chris@489 484 SimpleSPARQLQuery query(s, queryString);
Chris@439 485 query.setProgressReporter(reporter);
Chris@439 486
Chris@439 487 cerr << "Query will be: " << queryString.toStdString() << endl;
Chris@439 488
Chris@439 489 SimpleSPARQLQuery::ResultList results = query.execute();
Chris@439 490
Chris@439 491 if (!query.isOK()) {
Chris@439 492 m_errorString = query.getErrorString();
Chris@440 493 return;
Chris@439 494 }
Chris@439 495
Chris@439 496 if (query.wasCancelled()) {
Chris@439 497 m_errorString = "Query cancelled";
Chris@440 498 return;
Chris@439 499 }
Chris@439 500
Chris@449 501
Chris@449 502
Chris@449 503 /*
Chris@449 504
Chris@449 505 This function is now only used for sparse data (for dense data
Chris@449 506 we would be in getDataModelsDense instead).
Chris@449 507
Chris@449 508 For sparse data, the determining factors in deciding what model
Chris@449 509 to use are: Do the features have values? and Do the features
Chris@449 510 have duration?
Chris@449 511
Chris@449 512 We can run through the results and check off whether we find
Chris@449 513 values and duration for each of the source+type keys, and then
Chris@449 514 run through the source+type keys pushing each of the results
Chris@449 515 into a suitable model.
Chris@449 516
Chris@449 517 Unfortunately, at this point we do not yet have any actual
Chris@449 518 timing data (time/duration) -- just the time URI.
Chris@449 519
Chris@449 520 What we _could_ do is to create one of each type of model at the
Chris@449 521 start, for each of the source+type keys, and then push each
Chris@449 522 feature into the relevant model depending on what we find out
Chris@449 523 about it. Then return only non-empty models.
Chris@449 524
Chris@449 525
Chris@449 526 */
Chris@449 527
Chris@449 528 // Map from signal source to event type to dimensionality to
Chris@449 529 // presence of duration to model ptr. Whee!
Chris@449 530 std::map<QString, std::map<QString, std::map<int, std::map<bool, Model *> > > >
Chris@449 531 modelMap;
Chris@449 532
Chris@439 533 for (int i = 0; i < results.size(); ++i) {
Chris@439 534
Chris@440 535 QString source = results[i]["signal_source"].value;
Chris@449 536 QString type = results[i]["event_type"].value;
Chris@449 537 QString thinguri = results[i]["timed_thing"].value;
Chris@449 538
Chris@449 539 RealTime time;
Chris@449 540 RealTime duration;
Chris@439 541
Chris@449 542 bool haveTime = false;
Chris@449 543 bool haveDuration = false;
Chris@439 544
Chris@449 545 QString label = SimpleSPARQLQuery::singleResultQuery
Chris@489 546 (s, labelQueryString.arg(thinguri), "label").value;
Chris@449 547
Chris@489 548 SimpleSPARQLQuery rangeQuery(s, rangeQueryString.arg(thinguri));
Chris@450 549 SimpleSPARQLQuery::ResultList rangeResults = rangeQuery.execute();
Chris@450 550 if (!rangeResults.empty()) {
Chris@450 551 // std::cerr << rangeResults.size() << " range results" << std::endl;
Chris@450 552 time = RealTime::fromXsdDuration
Chris@450 553 (rangeResults[0]["time"].value.toStdString());
Chris@450 554 duration = RealTime::fromXsdDuration
Chris@450 555 (rangeResults[0]["duration"].value.toStdString());
Chris@450 556 // std::cerr << "duration string " << rangeResults[0]["duration"].value.toStdString() << std::endl;
Chris@449 557 haveTime = true;
Chris@450 558 haveDuration = true;
Chris@449 559 } else {
Chris@450 560 QString timestring = SimpleSPARQLQuery::singleResultQuery
Chris@489 561 (s, timeQueryString.arg(thinguri), "time").value;
Chris@450 562 if (timestring != "") {
Chris@450 563 time = RealTime::fromXsdDuration(timestring.toStdString());
Chris@449 564 haveTime = true;
Chris@449 565 }
Chris@449 566 }
Chris@439 567
Chris@439 568 QString valuestring = results[i]["value"].value;
Chris@449 569 std::vector<float> values;
Chris@449 570
Chris@439 571 if (valuestring != "") {
Chris@449 572 QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts);
Chris@449 573 for (int j = 0; j < vsl.size(); ++j) {
Chris@449 574 bool success = false;
Chris@449 575 float v = vsl[j].toFloat(&success);
Chris@449 576 if (success) values.push_back(v);
Chris@449 577 }
Chris@439 578 }
Chris@439 579
Chris@449 580 int dimensions = 1;
Chris@449 581 if (values.size() == 1) dimensions = 2;
Chris@449 582 else if (values.size() > 1) dimensions = 3;
Chris@449 583
Chris@449 584 Model *model = 0;
Chris@449 585
Chris@449 586 if (modelMap[source][type][dimensions].find(haveDuration) ==
Chris@449 587 modelMap[source][type][dimensions].end()) {
Chris@449 588
Chris@449 589 /*
Chris@449 590 std::cerr << "Creating new model: source = " << source.toStdString()
Chris@449 591 << ", type = " << type.toStdString() << ", dimensions = "
Chris@449 592 << dimensions << ", haveDuration = " << haveDuration
Chris@449 593 << ", time = " << time << ", duration = " << duration
Chris@449 594 << std::endl;
Chris@449 595 */
Chris@449 596
Chris@449 597 if (!haveDuration) {
Chris@449 598
Chris@449 599 if (dimensions == 1) {
Chris@449 600
Chris@449 601 // std::cerr << "SparseOneDimensionalModel" << std::endl;
Chris@449 602 model = new SparseOneDimensionalModel(m_sampleRate, 1, false);
Chris@449 603
Chris@449 604 } else if (dimensions == 2) {
Chris@449 605
Chris@449 606 // std::cerr << "SparseTimeValueModel" << std::endl;
Chris@449 607 model = new SparseTimeValueModel(m_sampleRate, 1, false);
Chris@449 608
Chris@449 609 } else {
Chris@449 610
Chris@449 611 // We don't have a three-dimensional sparse model,
Chris@449 612 // so use a note model. We do have some logic (in
Chris@449 613 // extractStructure below) for guessing whether
Chris@449 614 // this should after all have been a dense model,
Chris@449 615 // but it's hard to apply it because we don't have
Chris@449 616 // all the necessary timing data yet... hmm
Chris@449 617
Chris@449 618 // std::cerr << "NoteModel" << std::endl;
Chris@449 619 model = new NoteModel(m_sampleRate, 1, false);
Chris@449 620 }
Chris@449 621
Chris@449 622 } else { // haveDuration
Chris@449 623
Chris@449 624 if (dimensions == 1 || dimensions == 2) {
Chris@449 625
Chris@449 626 // If our units are frequency or midi pitch, we
Chris@449 627 // should be using a note model... hm
Chris@449 628
Chris@449 629 // std::cerr << "RegionModel" << std::endl;
Chris@449 630 model = new RegionModel(m_sampleRate, 1, false);
Chris@449 631
Chris@449 632 } else {
Chris@449 633
Chris@449 634 // We don't have a three-dimensional sparse model,
Chris@449 635 // so use a note model. We do have some logic (in
Chris@449 636 // extractStructure below) for guessing whether
Chris@449 637 // this should after all have been a dense model,
Chris@449 638 // but it's hard to apply it because we don't have
Chris@449 639 // all the necessary timing data yet... hmm
Chris@449 640
Chris@449 641 // std::cerr << "NoteModel" << std::endl;
Chris@449 642 model = new NoteModel(m_sampleRate, 1, false);
Chris@449 643 }
Chris@449 644 }
Chris@449 645
Chris@449 646 modelMap[source][type][dimensions][haveDuration] = model;
Chris@449 647 models.push_back(model);
Chris@449 648 }
Chris@449 649
Chris@449 650 model = modelMap[source][type][dimensions][haveDuration];
Chris@449 651
Chris@449 652 if (model) {
Chris@449 653 long ftime = RealTime::realTime2Frame(time, m_sampleRate);
Chris@449 654 long fduration = RealTime::realTime2Frame(duration, m_sampleRate);
Chris@449 655 fillModel(model, ftime, fduration, haveDuration, values, label);
Chris@439 656 }
Chris@439 657 }
Chris@439 658 }
Chris@439 659
Chris@439 660 void
Chris@449 661 RDFImporterImpl::fillModel(Model *model,
Chris@449 662 long ftime,
Chris@449 663 long fduration,
Chris@449 664 bool haveDuration,
Chris@449 665 std::vector<float> &values,
Chris@449 666 QString label)
Chris@449 667 {
Chris@492 668 std::cerr << "RDFImporterImpl::fillModel: adding point at frame " << ftime << std::endl;
Chris@492 669
Chris@449 670 SparseOneDimensionalModel *sodm =
Chris@449 671 dynamic_cast<SparseOneDimensionalModel *>(model);
Chris@449 672 if (sodm) {
Chris@449 673 SparseOneDimensionalModel::Point point(ftime, label);
Chris@449 674 sodm->addPoint(point);
Chris@449 675 return;
Chris@449 676 }
Chris@449 677
Chris@449 678 SparseTimeValueModel *stvm =
Chris@449 679 dynamic_cast<SparseTimeValueModel *>(model);
Chris@449 680 if (stvm) {
Chris@449 681 SparseTimeValueModel::Point point
Chris@449 682 (ftime, values.empty() ? 0.f : values[0], label);
Chris@449 683 stvm->addPoint(point);
Chris@449 684 return;
Chris@449 685 }
Chris@449 686
Chris@449 687 NoteModel *nm =
Chris@449 688 dynamic_cast<NoteModel *>(model);
Chris@449 689 if (nm) {
Chris@449 690 if (haveDuration) {
Chris@449 691 float value = 0.f, level = 1.f;
Chris@449 692 if (!values.empty()) {
Chris@449 693 value = values[0];
Chris@449 694 if (values.size() > 1) {
Chris@449 695 level = values[1];
Chris@449 696 }
Chris@449 697 }
Chris@449 698 NoteModel::Point point(ftime, value, fduration, level, label);
Chris@449 699 nm->addPoint(point);
Chris@449 700 } else {
Chris@449 701 float value = 0.f, duration = 1.f, level = 1.f;
Chris@449 702 if (!values.empty()) {
Chris@449 703 value = values[0];
Chris@449 704 if (values.size() > 1) {
Chris@449 705 duration = values[1];
Chris@449 706 if (values.size() > 2) {
Chris@449 707 level = values[2];
Chris@449 708 }
Chris@449 709 }
Chris@449 710 }
Chris@449 711 NoteModel::Point point(ftime, value, duration, level, label);
Chris@449 712 nm->addPoint(point);
Chris@449 713 }
Chris@449 714 return;
Chris@449 715 }
Chris@449 716
Chris@449 717 RegionModel *rm =
Chris@449 718 dynamic_cast<RegionModel *>(model);
Chris@449 719 if (rm) {
Chris@449 720 if (haveDuration) {
Chris@449 721 RegionModel::Point point
Chris@449 722 (ftime, values.empty() ? 0.f : values[0], fduration, label);
Chris@449 723 rm->addPoint(point);
Chris@449 724 } else {
Chris@449 725 // This won't actually happen -- we only create region models
Chris@449 726 // if we do have duration -- but just for completeness
Chris@449 727 float value = 0.f, duration = 1.f;
Chris@449 728 if (!values.empty()) {
Chris@449 729 value = values[0];
Chris@449 730 if (values.size() > 1) {
Chris@449 731 duration = values[1];
Chris@449 732 }
Chris@449 733 }
Chris@449 734 RegionModel::Point point(ftime, value, duration, label);
Chris@449 735 rm->addPoint(point);
Chris@449 736 }
Chris@449 737 return;
Chris@449 738 }
Chris@449 739
Chris@449 740 std::cerr << "WARNING: RDFImporterImpl::fillModel: Unknown or unexpected model type" << std::endl;
Chris@449 741 return;
Chris@449 742 }
Chris@449 743
Chris@490 744 RDFImporter::RDFDocumentType
Chris@490 745 RDFImporter::identifyDocumentType(QString url)
Chris@490 746 {
Chris@490 747 bool haveAudio = false;
Chris@490 748 bool haveAnnotations = false;
Chris@449 749
Chris@490 750 SimpleSPARQLQuery::Value value =
Chris@490 751 SimpleSPARQLQuery::singleResultQuery
Chris@490 752 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 753 QString
Chris@490 754 (" PREFIX mo: <http://purl.org/ontology/mo/> "
Chris@490 755 " SELECT ?url FROM <%1> "
Chris@490 756 " WHERE { ?signal a mo:Signal ; mo:available_as ?url } "
Chris@490 757 ).arg(url),
Chris@490 758 "url");
Chris@490 759
Chris@490 760 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 761 haveAudio = true;
Chris@490 762 }
Chris@490 763
Chris@490 764 value =
Chris@490 765 SimpleSPARQLQuery::singleResultQuery
Chris@490 766 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 767 QString
Chris@490 768 (" PREFIX event: <http://purl.org/NET/c4dm/event.owl#> "
Chris@490 769 " SELECT ?thing FROM <%1> "
Chris@490 770 " WHERE { ?thing event:time ?time } "
Chris@490 771 ).arg(url),
Chris@490 772 "thing");
Chris@490 773
Chris@490 774 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 775 haveAnnotations = true;
Chris@490 776 }
Chris@490 777
Chris@490 778 if (!haveAnnotations) {
Chris@490 779
Chris@490 780 value =
Chris@490 781 SimpleSPARQLQuery::singleResultQuery
Chris@490 782 (SimpleSPARQLQuery::QueryFromSingleSource,
Chris@490 783 QString
Chris@490 784 (" PREFIX af: <http://purl.org/ontology/af/> "
Chris@490 785 " SELECT ?thing FROM <%1> "
Chris@490 786 " WHERE { ?signal af:signal_feature ?thing } "
Chris@490 787 ).arg(url),
Chris@490 788 "thing");
Chris@490 789
Chris@490 790 if (value.type == SimpleSPARQLQuery::URIValue) {
Chris@490 791 haveAnnotations = true;
Chris@490 792 }
Chris@490 793 }
Chris@490 794
Chris@490 795 if (haveAudio) {
Chris@490 796 if (haveAnnotations) {
Chris@490 797 return AudioRefAndAnnotations;
Chris@490 798 } else {
Chris@490 799 return AudioRef;
Chris@490 800 }
Chris@490 801 } else {
Chris@490 802 if (haveAnnotations) {
Chris@490 803 return Annotations;
Chris@490 804 } else {
Chris@490 805 return OtherDocument;
Chris@490 806 }
Chris@490 807 }
Chris@492 808
Chris@492 809 SimpleSPARQLQuery::closeSingleSource(url);
Chris@490 810 }
Chris@490 811
Chris@490 812