annotate rdf/RDFImporter.cpp @ 480:3ffce691c9bf

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