annotate rdf/RDFImporter.cpp @ 489:82ab61fa9223

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