comparison rdf/RDFImporter.cpp @ 742:c10cb8782576 coreaudio_tests

Merge from branch "default"
author Chris Cannam
date Sun, 01 Jul 2012 11:53:00 +0100
parents 547b03533375
children e802e550a1f2
comparison
equal deleted inserted replaced
666:4efa7429cd85 742:c10cb8782576
2 2
3 /* 3 /*
4 Sonic Visualiser 4 Sonic Visualiser
5 An audio file viewer and annotation editor. 5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London. 6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2008 QMUL. 7 This file copyright 2008-2012 QMUL.
8 8
9 This program is free software; you can redistribute it and/or 9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as 10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the 11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file 12 License, or (at your option) any later version. See the file
19 #include <vector> 19 #include <vector>
20 20
21 #include <iostream> 21 #include <iostream>
22 #include <cmath> 22 #include <cmath>
23 23
24 #include "SimpleSPARQLQuery.h"
25
26 #include "base/ProgressReporter.h" 24 #include "base/ProgressReporter.h"
27 #include "base/RealTime.h" 25 #include "base/RealTime.h"
28 26
29 #include "data/model/SparseOneDimensionalModel.h" 27 #include "data/model/SparseOneDimensionalModel.h"
30 #include "data/model/SparseTimeValueModel.h" 28 #include "data/model/SparseTimeValueModel.h"
36 34
37 #include "data/fileio/FileSource.h" 35 #include "data/fileio/FileSource.h"
38 #include "data/fileio/CachedFile.h" 36 #include "data/fileio/CachedFile.h"
39 #include "data/fileio/FileFinder.h" 37 #include "data/fileio/FileFinder.h"
40 38
39 #include <dataquay/BasicStore.h>
40 #include <dataquay/PropertyObject.h>
41
42 using Dataquay::Uri;
43 using Dataquay::Node;
44 using Dataquay::Nodes;
45 using Dataquay::Triple;
46 using Dataquay::Triples;
47 using Dataquay::BasicStore;
48 using Dataquay::PropertyObject;
49
41 using std::cerr; 50 using std::cerr;
42 using std::endl; 51 using std::endl;
43 52
44 class RDFImporterImpl 53 class RDFImporterImpl
45 { 54 {
53 QString getErrorString() const; 62 QString getErrorString() const;
54 63
55 std::vector<Model *> getDataModels(ProgressReporter *); 64 std::vector<Model *> getDataModels(ProgressReporter *);
56 65
57 protected: 66 protected:
67 BasicStore *m_store;
68 Uri expand(QString s) { return m_store->expand(s); }
69
58 QString m_uristring; 70 QString m_uristring;
59 QString m_errorString; 71 QString m_errorString;
60 std::map<QString, Model *> m_audioModelMap; 72 std::map<QString, Model *> m_audioModelMap;
61 int m_sampleRate; 73 int m_sampleRate;
62 74
63 std::map<Model *, std::map<QString, float> > m_labelValueMap; 75 std::map<Model *, std::map<QString, float> > m_labelValueMap;
64 76
65 static bool m_prefixesLoaded;
66 static void loadPrefixes(ProgressReporter *reporter);
67
68 void getDataModelsAudio(std::vector<Model *> &, ProgressReporter *); 77 void getDataModelsAudio(std::vector<Model *> &, ProgressReporter *);
69 void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *); 78 void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *);
70 void getDataModelsDense(std::vector<Model *> &, ProgressReporter *); 79 void getDataModelsDense(std::vector<Model *> &, ProgressReporter *);
71 80
72 void getDenseModelTitle(Model *, QString, QString); 81 void getDenseModelTitle(Model *, QString, QString);
76 int &hopSize, int &width, int &height); 85 int &hopSize, int &width, int &height);
77 86
78 void fillModel(Model *, long, long, bool, std::vector<float> &, QString); 87 void fillModel(Model *, long, long, bool, std::vector<float> &, QString);
79 }; 88 };
80 89
81 bool RDFImporterImpl::m_prefixesLoaded = false;
82
83 QString 90 QString
84 RDFImporter::getKnownExtensions() 91 RDFImporter::getKnownExtensions()
85 { 92 {
86 return "*.rdf *.n3 *.ttl"; 93 return "*.rdf *.n3 *.ttl";
87 } 94 }
119 { 126 {
120 return m_d->getDataModels(r); 127 return m_d->getDataModels(r);
121 } 128 }
122 129
123 RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) : 130 RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) :
131 m_store(new BasicStore),
124 m_uristring(uri), 132 m_uristring(uri),
125 m_sampleRate(sampleRate) 133 m_sampleRate(sampleRate)
126 { 134 {
135 //!!! retrieve data if remote... then
136
137 m_store->addPrefix("mo", Uri("http://purl.org/ontology/mo/"));
138 m_store->addPrefix("af", Uri("http://purl.org/ontology/af/"));
139 m_store->addPrefix("dc", Uri("http://purl.org/dc/elements/1.1/"));
140 m_store->addPrefix("tl", Uri("http://purl.org/NET/c4dm/timeline.owl#"));
141 m_store->addPrefix("event", Uri("http://purl.org/NET/c4dm/event.owl#"));
142 m_store->addPrefix("rdfs", Uri("http://www.w3.org/2000/01/rdf-schema#"));
143
144 try {
145 QUrl url;
146 if (uri.startsWith("file:")) {
147 url = QUrl(uri);
148 } else {
149 url = QUrl::fromLocalFile(uri);
150 }
151 m_store->import(url, BasicStore::ImportIgnoreDuplicates);
152 } catch (std::exception &e) {
153 m_errorString = e.what();
154 }
127 } 155 }
128 156
129 RDFImporterImpl::~RDFImporterImpl() 157 RDFImporterImpl::~RDFImporterImpl()
130 { 158 {
131 SimpleSPARQLQuery::closeSingleSource(m_uristring); 159 delete m_store;
132 } 160 }
133 161
134 bool 162 bool
135 RDFImporterImpl::isOK() 163 RDFImporterImpl::isOK()
136 { 164 {
144 } 172 }
145 173
146 std::vector<Model *> 174 std::vector<Model *>
147 RDFImporterImpl::getDataModels(ProgressReporter *reporter) 175 RDFImporterImpl::getDataModels(ProgressReporter *reporter)
148 { 176 {
149 loadPrefixes(reporter);
150
151 std::vector<Model *> models; 177 std::vector<Model *> models;
152 178
153 getDataModelsAudio(models, reporter); 179 getDataModelsAudio(models, reporter);
154 180
155 if (m_sampleRate == 0) { 181 if (m_sampleRate == 0) {
156 m_errorString = QString("Invalid audio data model (is audio file format supported?)"); 182 m_errorString = QString("Invalid audio data model (is audio file format supported?)");
157 std::cerr << m_errorString.toStdString() << std::endl; 183 std::cerr << m_errorString << std::endl;
158 return models; 184 return models;
159 } 185 }
160 186
161 QString error; 187 QString error;
162 188
183 209
184 void 210 void
185 RDFImporterImpl::getDataModelsAudio(std::vector<Model *> &models, 211 RDFImporterImpl::getDataModelsAudio(std::vector<Model *> &models,
186 ProgressReporter *reporter) 212 ProgressReporter *reporter)
187 { 213 {
188 SimpleSPARQLQuery query 214 Nodes sigs = m_store->match
189 (SimpleSPARQLQuery::QueryFromSingleSource, 215 (Triple(Node(), Uri("a"), expand("mo:Signal"))).subjects();
190 QString 216
191 ( 217 foreach (Node sig, sigs) {
192 " PREFIX mo: <http://purl.org/ontology/mo/> "
193 " SELECT ?signal ?source FROM <%1> "
194 " WHERE { ?source a mo:AudioFile . "
195 " ?signal a mo:Signal . "
196 " ?source mo:encodes ?signal } "
197 )
198 .arg(m_uristring));
199
200 SimpleSPARQLQuery::ResultList results = query.execute();
201
202 if (results.empty()) {
203
204 SimpleSPARQLQuery query2
205 (SimpleSPARQLQuery::QueryFromSingleSource,
206 QString
207 (
208 " PREFIX mo: <http://purl.org/ontology/mo/> "
209 " SELECT ?signal ?source FROM <%1> "
210 " WHERE { ?signal a mo:Signal ; mo:available_as ?source } "
211 )
212 .arg(m_uristring));
213 218
214 results = query.execute(); 219 Node file = m_store->complete(Triple(Node(), expand("mo:encodes"), sig));
215 } 220 if (file == Node()) {
216 221 file = m_store->complete(Triple(sig, expand("mo:available_as"), Node()));
217 for (int i = 0; i < results.size(); ++i) { 222 }
218 223 if (file == Node()) {
219 QString signal = results[i]["signal"].value; 224 std::cerr << "RDFImporterImpl::getDataModelsAudio: ERROR: No source for signal " << sig << std::endl;
220 QString source = results[i]["source"].value; 225 continue;
221 226 }
222 std::cerr << "NOTE: Seeking signal source \"" << source.toStdString() 227
223 << "\"..." << std::endl; 228 QString signal = sig.value;
229 QString source = file.value;
230
231 SVDEBUG << "NOTE: Seeking signal source \"" << source
232 << "\"..." << endl;
224 233
225 FileSource *fs = new FileSource(source, reporter); 234 FileSource *fs = new FileSource(source, reporter);
226 if (fs->isAvailable()) { 235 if (fs->isAvailable()) {
227 std::cerr << "NOTE: Source is available: Local filename is \"" 236 SVDEBUG << "NOTE: Source is available: Local filename is \""
228 << fs->getLocalFilename().toStdString() 237 << fs->getLocalFilename()
229 << "\"..." << std::endl; 238 << "\"..." << endl;
230 } 239 }
231 240
232 #ifdef NO_SV_GUI 241 #ifdef NO_SV_GUI
233 if (!fs->isAvailable()) { 242 if (!fs->isAvailable()) {
234 m_errorString = QString("Signal source \"%1\" is not available").arg(source); 243 m_errorString = QString("Signal source \"%1\" is not available").arg(source);
235 delete fs; 244 delete fs;
236 continue; 245 continue;
237 } 246 }
238 #else 247 #else
239 if (!fs->isAvailable()) { 248 if (!fs->isAvailable()) {
240 std::cerr << "NOTE: Signal source \"" << source.toStdString() 249 SVDEBUG << "NOTE: Signal source \"" << source
241 << "\" is not available, using file finder..." << std::endl; 250 << "\" is not available, using file finder..." << endl;
242 FileFinder *ff = FileFinder::getInstance(); 251 FileFinder *ff = FileFinder::getInstance();
243 if (ff) { 252 if (ff) {
244 QString path = ff->find(FileFinder::AudioFile, 253 QString path = ff->find(FileFinder::AudioFile,
245 fs->getLocation(), 254 fs->getLocation(),
246 m_uristring); 255 m_uristring);
263 reporter->setMessage(RDFImporter::tr("Importing audio referenced in RDF...")); 272 reporter->setMessage(RDFImporter::tr("Importing audio referenced in RDF..."));
264 } 273 }
265 fs->waitForData(); 274 fs->waitForData();
266 WaveFileModel *newModel = new WaveFileModel(*fs, m_sampleRate); 275 WaveFileModel *newModel = new WaveFileModel(*fs, m_sampleRate);
267 if (newModel->isOK()) { 276 if (newModel->isOK()) {
268 std::cerr << "Successfully created wave file model from source at \"" << source.toStdString() << "\"" << std::endl; 277 std::cerr << "Successfully created wave file model from source at \"" << source << "\"" << std::endl;
269 models.push_back(newModel); 278 models.push_back(newModel);
270 m_audioModelMap[signal] = newModel; 279 m_audioModelMap[signal] = newModel;
271 if (m_sampleRate == 0) { 280 if (m_sampleRate == 0) {
272 m_sampleRate = newModel->getSampleRate(); 281 m_sampleRate = newModel->getSampleRate();
273 } 282 }
285 { 294 {
286 if (reporter) { 295 if (reporter) {
287 reporter->setMessage(RDFImporter::tr("Importing dense signal data from RDF...")); 296 reporter->setMessage(RDFImporter::tr("Importing dense signal data from RDF..."));
288 } 297 }
289 298
290 SimpleSPARQLQuery query 299 Nodes sigFeatures = m_store->match
291 (SimpleSPARQLQuery::QueryFromSingleSource, 300 (Triple(Node(), expand("af:signal_feature"), Node())).objects();
292 QString 301
293 ( 302 foreach (Node sf, sigFeatures) {
294 " PREFIX mo: <http://purl.org/ontology/mo/>" 303
295 " PREFIX af: <http://purl.org/ontology/af/>" 304 if (sf.type != Node::URI && sf.type != Node::Blank) continue;
296 305
297 " SELECT ?feature ?feature_signal_type ?value " 306 Node t = m_store->complete(Triple(sf, expand("a"), Node()));
298 " FROM <%1> " 307 Node v = m_store->complete(Triple(sf, expand("af:value"), Node()));
299 308
300 " WHERE { " 309 QString feature = sf.value;
301 310 QString type = t.value;
302 " ?signal af:signal_feature ?feature . " 311 QString value = v.value;
303 312
304 " ?feature a ?feature_signal_type ; " 313 if (type == "" || value == "") continue;
305 " af:value ?value . "
306
307 " } "
308 )
309 .arg(m_uristring));
310
311 SimpleSPARQLQuery::ResultList results = query.execute();
312
313 if (!query.isOK()) {
314 m_errorString = query.getErrorString();
315 return;
316 }
317
318 if (query.wasCancelled()) {
319 m_errorString = "Query cancelled";
320 return;
321 }
322
323 for (int i = 0; i < results.size(); ++i) {
324
325 QString feature = results[i]["feature"].value;
326 QString type = results[i]["feature_signal_type"].value;
327 QString value = results[i]["value"].value;
328 314
329 int sampleRate = 0; 315 int sampleRate = 0;
330 int windowLength = 0; 316 int windowLength = 0;
331 int hopSize = 0; 317 int hopSize = 0;
332 int width = 0; 318 int width = 0;
408 void 394 void
409 RDFImporterImpl::getDenseModelTitle(Model *m, 395 RDFImporterImpl::getDenseModelTitle(Model *m,
410 QString featureUri, 396 QString featureUri,
411 QString featureTypeUri) 397 QString featureTypeUri)
412 { 398 {
413 QString titleQuery = QString 399 Node n = m_store->complete
414 ( 400 (Triple(Uri(featureUri), expand("dc:title"), Node()));
415 " PREFIX dc: <http://purl.org/dc/elements/1.1/> " 401
416 " SELECT ?title " 402 if (n.type == Node::Literal && n.value != "") {
417 " FROM <%1> " 403 SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal) \"" << n.value << "\"" << endl;
418 " WHERE { " 404 m->setObjectName(n.value);
419 " <%2> dc:title ?title . "
420 " } "
421 ).arg(m_uristring);
422
423 SimpleSPARQLQuery::Value v;
424
425 v = SimpleSPARQLQuery::singleResultQuery
426 (SimpleSPARQLQuery::QueryFromSingleSource,
427 titleQuery.arg(featureUri),
428 "title");
429
430 if (v.value != "") {
431 std::cerr << "RDFImporterImpl::getDenseModelTitle: Title (from signal) \"" << v.value.toStdString() << "\"" << std::endl;
432 m->setObjectName(v.value);
433 return; 405 return;
434 } 406 }
435 407
436 v = SimpleSPARQLQuery::singleResultQuery 408 n = m_store->complete
437 (SimpleSPARQLQuery::QueryFromSingleSource, 409 (Triple(Uri(featureTypeUri), expand("dc:title"), Node()));
438 titleQuery.arg(featureTypeUri), 410
439 "title"); 411 if (n.type == Node::Literal && n.value != "") {
440 412 SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal type) \"" << n.value << "\"" << endl;
441 if (v.value != "") { 413 m->setObjectName(n.value);
442 std::cerr << "RDFImporterImpl::getDenseModelTitle: Title (from signal type) \"" << v.value.toStdString() << "\"" << std::endl;
443 m->setObjectName(v.value);
444 return; 414 return;
445 } 415 }
446 416
447 std::cerr << "RDFImporterImpl::getDenseModelTitle: No title available for feature <" << featureUri.toStdString() << ">" << std::endl; 417 SVDEBUG << "RDFImporterImpl::getDenseModelTitle: No title available for feature <" << featureUri << ">" << endl;
448 } 418 }
449 419
450 void 420 void
451 RDFImporterImpl::getDenseFeatureProperties(QString featureUri, 421 RDFImporterImpl::getDenseFeatureProperties(QString featureUri,
452 int &sampleRate, int &windowLength, 422 int &sampleRate, int &windowLength,
453 int &hopSize, int &width, int &height) 423 int &hopSize, int &width, int &height)
454 { 424 {
455 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource; 425 Node dim = m_store->complete
456 426 (Triple(Uri(featureUri), expand("af:dimensions"), Node()));
457 QString dimensionsQuery 427
458 ( 428 cerr << "Dimensions = \"" << dim.value << "\"" << endl;
459 " PREFIX mo: <http://purl.org/ontology/mo/>" 429
460 " PREFIX af: <http://purl.org/ontology/af/>" 430 if (dim.type == Node::Literal && dim.value != "") {
461 431 QStringList dl = dim.value.split(" ");
462 " SELECT ?dimensions " 432 if (dl.empty()) dl.push_back(dim.value);
463 " FROM <%1> "
464
465 " WHERE { "
466
467 " <%2> af:dimensions ?dimensions . "
468
469 " } "
470 );
471
472 SimpleSPARQLQuery::Value dimensionsValue =
473 SimpleSPARQLQuery::singleResultQuery
474 (s, dimensionsQuery.arg(m_uristring).arg(featureUri), "dimensions");
475
476 cerr << "Dimensions = \"" << dimensionsValue.value.toStdString() << "\""
477 << endl;
478
479 if (dimensionsValue.value != "") {
480 QStringList dl = dimensionsValue.value.split(" ");
481 if (dl.empty()) dl.push_back(dimensionsValue.value);
482 if (dl.size() > 0) height = dl[0].toInt(); 433 if (dl.size() > 0) height = dl[0].toInt();
483 if (dl.size() > 1) width = dl[1].toInt(); 434 if (dl.size() > 1) width = dl[1].toInt();
484 } 435 }
485 436
486 QString queryTemplate 437 // Looking for rate, hop, window from:
487 ( 438 //
488 " PREFIX mo: <http://purl.org/ontology/mo/>" 439 // ?feature mo:time ?time .
489 " PREFIX af: <http://purl.org/ontology/af/>" 440 // ?time a tl:Interval .
490 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>" 441 // ?time tl:onTimeLine ?timeline .
491 442 // ?map tl:rangeTimeLine ?timeline .
492 " SELECT ?%3 " 443 // ?map tl:sampleRate ?rate .
493 " FROM <%1> " 444 // ?map tl:hopSize ?hop .
494 445 // ?map tl:windowLength ?window .
495 " WHERE { " 446
496 447 Node interval = m_store->complete(Triple(Uri(featureUri), expand("mo:time"), Node()));
497 " <%2> mo:time ?time . " 448
498 449 if (!m_store->contains(Triple(interval, expand("a"), expand("tl:Interval")))) {
499 " ?time a tl:Interval ; " 450 cerr << "RDFImporterImpl::getDenseFeatureProperties: Feature time node "
500 " tl:onTimeLine ?timeline . " 451 << interval << " is not a tl:Interval" << endl;
501 452 return;
502 " ?map tl:rangeTimeLine ?timeline . " 453 }
503 454
504 " ?map tl:%3 ?%3 . " 455 Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
505 456
506 " } " 457 if (tl == Node()) {
507 ); 458 cerr << "RDFImporterImpl::getDenseFeatureProperties: Interval node "
508 459 << interval << " lacks tl:onTimeLine property" << endl;
509 // Another laborious workaround for rasqal's failure to handle 460 return;
510 // multiple optionals properly 461 }
511 462
512 SimpleSPARQLQuery::Value srValue = 463 Node map = m_store->complete(Triple(Node(), expand("tl:rangeTimeLine"), tl));
513 SimpleSPARQLQuery::singleResultQuery(s, 464
514 queryTemplate 465 if (map == Node()) {
515 .arg(m_uristring).arg(featureUri) 466 cerr << "RDFImporterImpl::getDenseFeatureProperties: No map for "
516 .arg("sampleRate"), 467 << "timeline node " << tl << endl;
517 "sampleRate"); 468 }
518 if (srValue.value != "") { 469
519 sampleRate = srValue.value.toInt(); 470 PropertyObject po(m_store, "tl:", map);
520 } 471
521 472 if (po.hasProperty("sampleRate")) {
522 SimpleSPARQLQuery::Value hopValue = 473 sampleRate = po.getProperty("sampleRate").toInt();
523 SimpleSPARQLQuery::singleResultQuery(s, 474 }
524 queryTemplate 475 if (po.hasProperty("hopSize")) {
525 .arg(m_uristring).arg(featureUri) 476 hopSize = po.getProperty("hopSize").toInt();
526 .arg("hopSize"), 477 }
527 "hopSize"); 478 if (po.hasProperty("windowLength")) {
528 if (srValue.value != "") { 479 windowLength = po.getProperty("windowLength").toInt();
529 hopSize = hopValue.value.toInt();
530 }
531
532 SimpleSPARQLQuery::Value winValue =
533 SimpleSPARQLQuery::singleResultQuery(s,
534 queryTemplate
535 .arg(m_uristring).arg(featureUri)
536 .arg("windowLength"),
537 "windowLength");
538 if (winValue.value != "") {
539 windowLength = winValue.value.toInt();
540 } 480 }
541 481
542 cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl; 482 cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl;
543 } 483 }
544 484
548 { 488 {
549 if (reporter) { 489 if (reporter) {
550 reporter->setMessage(RDFImporter::tr("Importing event data from RDF...")); 490 reporter->setMessage(RDFImporter::tr("Importing event data from RDF..."));
551 } 491 }
552 492
553 SimpleSPARQLQuery::QueryType s = SimpleSPARQLQuery::QueryFromSingleSource;
554
555 // Our query is intended to retrieve every thing that has a time,
556 // and every feature type and value associated with a thing that
557 // has a time.
558
559 // We will then need to refine this big bag of results into a set
560 // of data models.
561
562 // Results that have different source signals should go into
563 // different models.
564
565 // Results that have different feature types should go into
566 // different models.
567
568 // Results that are sparse should go into different models from
569 // those that are dense (we need to examine the timestamps to
570 // establish this -- if the timestamps are regular, the results
571 // are dense -- so we can't do it as we go along, only after
572 // collecting all results).
573
574 // Timed things that have features associated with them should not
575 // appear directly in any model -- their features should appear
576 // instead -- and these should be different models from those used
577 // for timed things that do not have features.
578
579 // As we load the results, we'll push them into a partially
580 // structured container that maps from source signal (URI as
581 // string) -> feature type (likewise) -> time -> list of values.
582 // If the source signal or feature type is unavailable, the empty
583 // string will do.
584
585 QString prefixes = QString(
586 " PREFIX event: <http://purl.org/NET/c4dm/event.owl#>"
587 " PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>"
588 " PREFIX mo: <http://purl.org/ontology/mo/>"
589 " PREFIX af: <http://purl.org/ontology/af/>"
590 " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
591 );
592
593 QString queryString = prefixes + QString(
594
595 " SELECT ?signal ?timed_thing ?timeline ?event_type ?value"
596 " FROM <%1>"
597
598 " WHERE {"
599
600 " ?signal a mo:Signal ."
601
602 " ?signal mo:time ?interval ."
603 " ?interval tl:onTimeLine ?timeline ."
604 " ?time tl:onTimeLine ?timeline ."
605 " ?timed_thing event:time ?time ."
606 " ?timed_thing a ?event_type ."
607
608 " OPTIONAL {"
609 " ?timed_thing af:feature ?value"
610 " }"
611 " }"
612
613 ).arg(m_uristring);
614
615 //!!! NB we're using rather old terminology for these things, apparently:
616 // beginsAt -> start
617 // onTimeLine -> timeline
618
619 QString timeQueryString = prefixes + QString(
620
621 " SELECT ?time FROM <%1> "
622 " WHERE { "
623 " <%2> event:time ?t . "
624 " ?t tl:at ?time . "
625 " } "
626
627 ).arg(m_uristring);
628
629 QString rangeQueryString = prefixes + QString(
630
631 " SELECT ?time ?duration FROM <%1> "
632 " WHERE { "
633 " <%2> event:time ?t . "
634 " ?t tl:beginsAt ?time . "
635 " ?t tl:duration ?duration . "
636 " } "
637
638 ).arg(m_uristring);
639
640 QString labelQueryString = prefixes + QString(
641
642 " SELECT ?label FROM <%1> "
643 " WHERE { "
644 " <%2> rdfs:label ?label . "
645 " } "
646
647 ).arg(m_uristring);
648
649 QString textQueryString = prefixes + QString(
650
651 " SELECT ?label FROM <%1> "
652 " WHERE { "
653 " <%2> af:text ?label . "
654 " } "
655
656 ).arg(m_uristring);
657
658 SimpleSPARQLQuery query(s, queryString);
659 query.setProgressReporter(reporter);
660
661 // cerr << "Query will be: " << queryString.toStdString() << endl;
662
663 SimpleSPARQLQuery::ResultList results = query.execute();
664
665 if (!query.isOK()) {
666 m_errorString = query.getErrorString();
667 return;
668 }
669
670 if (query.wasCancelled()) {
671 m_errorString = "Query cancelled";
672 return;
673 }
674
675 /* 493 /*
676 This function is now only used for sparse data (for dense data 494 This function is only used for sparse data (for dense data we
677 we would be in getDataModelsDense instead). 495 would be in getDataModelsDense instead).
678 496
679 For sparse data, the determining factors in deciding what model 497 Our query is intended to retrieve every thing that has a time,
680 to use are: Do the features have values? and Do the features 498 and every feature type and value associated with a thing that
681 have duration? 499 has a time.
682 500
683 We can run through the results and check off whether we find 501 We will then need to refine this big bag of results into a set
684 values and duration for each of the source+type keys, and then 502 of data models.
685 run through the source+type keys pushing each of the results 503
686 into a suitable model. 504 Results that have different source signals should go into
687 505 different models.
688 Unfortunately, at this point we do not yet have any actual 506
689 timing data (time/duration) -- just the time URI. 507 Results that have different feature types should go into
690 508 different models.
691 What we _could_ do is to create one of each type of model at the
692 start, for each of the source+type keys, and then push each
693 feature into the relevant model depending on what we find out
694 about it. Then return only non-empty models.
695 */ 509 */
510
511 Nodes sigs = m_store->match
512 (Triple(Node(), expand("a"), expand("mo:Signal"))).subjects();
696 513
697 // Map from timeline uri to event type to dimensionality to 514 // Map from timeline uri to event type to dimensionality to
698 // presence of duration to model ptr. Whee! 515 // presence of duration to model ptr. Whee!
699 std::map<QString, std::map<QString, std::map<int, std::map<bool, Model *> > > > 516 std::map<QString, std::map<QString, std::map<int, std::map<bool, Model *> > > >
700 modelMap; 517 modelMap;
701 518
702 for (int i = 0; i < results.size(); ++i) { 519 foreach (Node sig, sigs) {
703
704 if (i % 4 == 0) {
705 if (reporter) reporter->setProgress(i/4);
706 }
707
708 QString source = results[i]["signal"].value;
709 QString timeline = results[i]["timeline"].value;
710 QString type = results[i]["event_type"].value;
711 QString thinguri = results[i]["timed_thing"].value;
712 520
713 RealTime time; 521 Node interval = m_store->complete(Triple(sig, expand("mo:time"), Node()));
714 RealTime duration; 522 if (interval == Node()) continue;
715 523
716 bool haveTime = false; 524 Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
717 bool haveDuration = false; 525 if (tl == Node()) continue;
718 526
719 QString label = ""; 527 Nodes times = m_store->match(Triple(Node(), expand("tl:onTimeLine"), tl)).subjects();
720 bool text = (type.contains("Text") || type.contains("text")); // Ha, ha 528
721 529 foreach (Node tn, times) {
722 if (text) { 530
723 label = SimpleSPARQLQuery::singleResultQuery 531 Nodes timedThings = m_store->match(Triple(Node(), expand("event:time"), tn)).subjects();
724 (s, textQueryString.arg(thinguri), "label").value; 532
725 } 533 foreach (Node thing, timedThings) {
726 534
727 if (label == "") { 535 Node typ = m_store->complete(Triple(thing, expand("a"), Node()));
728 label = SimpleSPARQLQuery::singleResultQuery 536 if (typ == Node()) continue;
729 (s, labelQueryString.arg(thinguri), "label").value; 537
730 } 538 Node valu = m_store->complete(Triple(thing, expand("af:feature"), Node()));
731 539
732 SimpleSPARQLQuery rangeQuery(s, rangeQueryString.arg(thinguri)); 540 QString source = sig.value;
733 SimpleSPARQLQuery::ResultList rangeResults = rangeQuery.execute(); 541 QString timeline = tl.value;
734 if (!rangeResults.empty()) { 542 QString type = typ.value;
735 // std::cerr << rangeResults.size() << " range results" << std::endl; 543 QString thinguri = thing.value;
736 time = RealTime::fromXsdDuration 544
737 (rangeResults[0]["time"].value.toStdString()); 545 /*
738 duration = RealTime::fromXsdDuration 546 For sparse data, the determining factors in deciding
739 (rangeResults[0]["duration"].value.toStdString()); 547 what model to use are: Do the features have values?
740 // std::cerr << "duration string " << rangeResults[0]["duration"].value.toStdString() << std::endl; 548 and Do the features have duration?
741 haveTime = true; 549
742 haveDuration = true; 550 We can run through the results and check off whether
743 } else { 551 we find values and duration for each of the
744 QString timestring = SimpleSPARQLQuery::singleResultQuery 552 source+type keys, and then run through the
745 (s, timeQueryString.arg(thinguri), "time").value; 553 source+type keys pushing each of the results into a
746 // std::cerr << "timestring = " << timestring.toStdString() << std::endl; 554 suitable model.
747 if (timestring != "") { 555
748 time = RealTime::fromXsdDuration(timestring.toStdString()); 556 Unfortunately, at this point we do not yet have any
749 haveTime = true; 557 actual timing data (time/duration) -- just the time
750 } 558 URI.
751 } 559
752 560 What we _could_ do is to create one of each type of
753 QString valuestring = results[i]["value"].value; 561 model at the start, for each of the source+type
754 std::vector<float> values; 562 keys, and then push each feature into the relevant
755 563 model depending on what we find out about it. Then
756 if (valuestring != "") { 564 return only non-empty models.
757 QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts); 565 */
758 for (int j = 0; j < vsl.size(); ++j) { 566
759 bool success = false; 567 QString label = "";
760 float v = vsl[j].toFloat(&success); 568 bool text = (type.contains("Text") || type.contains("text")); // Ha, ha
761 if (success) values.push_back(v); 569 bool note = (type.contains("Note") || type.contains("note")); // Guffaw
762 } 570
763 } 571 if (text) {
764 572 label = m_store->complete(Triple(thing, expand("af:text"), Node())).value;
765 int dimensions = 1; 573 }
766 if (values.size() == 1) dimensions = 2; 574
767 else if (values.size() > 1) dimensions = 3; 575 if (label == "") {
768 576 label = m_store->complete(Triple(thing, expand("rdfs:label"), Node())).value;
769 Model *model = 0; 577 }
770 578
771 if (modelMap[timeline][type][dimensions].find(haveDuration) == 579 RealTime time;
772 modelMap[timeline][type][dimensions].end()) { 580 RealTime duration;
581
582 bool haveTime = false;
583 bool haveDuration = false;
584
585 Node at = m_store->complete(Triple(tn, expand("tl:at"), Node()));
586
587 if (at != Node()) {
588 time = RealTime::fromXsdDuration(at.value.toStdString());
589 haveTime = true;
590 } else {
591 //!!! NB we're using rather old terminology for these things, apparently:
592 // beginsAt -> start
593 // onTimeLine -> timeline
594
595 Node start = m_store->complete(Triple(tn, expand("tl:beginsAt"), Node()));
596 Node dur = m_store->complete(Triple(tn, expand("tl:duration"), Node()));
597 if (start != Node() && dur != Node()) {
598 time = RealTime::fromXsdDuration
599 (start.value.toStdString());
600 duration = RealTime::fromXsdDuration
601 (dur.value.toStdString());
602 haveTime = haveDuration = true;
603 }
604 }
605
606 QString valuestring = valu.value;
607 std::vector<float> values;
608
609 if (valuestring != "") {
610 QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts);
611 for (int j = 0; j < vsl.size(); ++j) {
612 bool success = false;
613 float v = vsl[j].toFloat(&success);
614 if (success) values.push_back(v);
615 }
616 }
617
618 int dimensions = 1;
619 if (values.size() == 1) dimensions = 2;
620 else if (values.size() > 1) dimensions = 3;
621
622 Model *model = 0;
623
624 if (modelMap[timeline][type][dimensions].find(haveDuration) ==
625 modelMap[timeline][type][dimensions].end()) {
773 626
774 /* 627 /*
775 std::cerr << "Creating new model: source = " << source.toStdString() 628 SVDEBUG << "Creating new model: source = " << source << ", type = " << type << ", dimensions = "
776 << ", type = " << type.toStdString() << ", dimensions = "
777 << dimensions << ", haveDuration = " << haveDuration 629 << dimensions << ", haveDuration = " << haveDuration
778 << ", time = " << time << ", duration = " << duration 630 << ", time = " << time << ", duration = " << duration
779 << std::endl; 631 << endl;
780 */ 632 */
781 633
782 if (!haveDuration) { 634 if (!haveDuration) {
783 635
784 if (dimensions == 1) { 636 if (dimensions == 1) {
785 637 if (text) {
786 if (text) { 638 model = new TextModel(m_sampleRate, 1, false);
787 639 } else {
788 model = new TextModel(m_sampleRate, 1, false); 640 model = new SparseOneDimensionalModel(m_sampleRate, 1, false);
789 641 }
790 } else { 642 } else if (dimensions == 2) {
791 643 if (text) {
792 model = new SparseOneDimensionalModel(m_sampleRate, 1, false); 644 model = new TextModel(m_sampleRate, 1, false);
645 } else {
646 model = new SparseTimeValueModel(m_sampleRate, 1, false);
647 }
648 } else {
649 // We don't have a three-dimensional sparse model,
650 // so use a note model. We do have some logic (in
651 // extractStructure below) for guessing whether
652 // this should after all have been a dense model,
653 // but it's hard to apply it because we don't have
654 // all the necessary timing data yet... hmm
655 model = new NoteModel(m_sampleRate, 1, false);
656 }
657
658 } else { // haveDuration
659
660 if (note || (dimensions > 2)) {
661 model = new NoteModel(m_sampleRate, 1, false);
662 } else {
663 // If our units are frequency or midi pitch, we
664 // should be using a note model... hm
665 model = new RegionModel(m_sampleRate, 1, false);
666 }
793 } 667 }
794 668
795 } else if (dimensions == 2) { 669 model->setRDFTypeURI(type);
796 670
797 if (text) { 671 if (m_audioModelMap.find(source) != m_audioModelMap.end()) {
798 672 std::cerr << "source model for " << model << " is " << m_audioModelMap[source] << std::endl;
799 model = new TextModel(m_sampleRate, 1, false); 673 model->setSourceModel(m_audioModelMap[source]);
800
801 } else {
802
803 model = new SparseTimeValueModel(m_sampleRate, 1, false);
804 } 674 }
805 675
806 } else { 676 QString title = m_store->complete
807 677 (Triple(typ, expand("dc:title"), Node())).value;
808 // We don't have a three-dimensional sparse model, 678 if (title == "") {
809 // so use a note model. We do have some logic (in 679 // take it from the end of the event type
810 // extractStructure below) for guessing whether 680 title = type;
811 // this should after all have been a dense model, 681 title.replace(QRegExp("^.*[/#]"), "");
812 // but it's hard to apply it because we don't have 682 }
813 // all the necessary timing data yet... hmm 683 model->setObjectName(title);
814 684
815 model = new NoteModel(m_sampleRate, 1, false); 685 modelMap[timeline][type][dimensions][haveDuration] = model;
816 } 686 models.push_back(model);
817 687 }
818 } else { // haveDuration 688
819 689 model = modelMap[timeline][type][dimensions][haveDuration];
820 if (dimensions == 1 || dimensions == 2) { 690
821 691 if (model) {
822 // If our units are frequency or midi pitch, we 692 long ftime = RealTime::realTime2Frame(time, m_sampleRate);
823 // should be using a note model... hm 693 long fduration = RealTime::realTime2Frame(duration, m_sampleRate);
824 694 fillModel(model, ftime, fduration, haveDuration, values, label);
825 model = new RegionModel(m_sampleRate, 1, false); 695 }
826 696 }
827 } else {
828
829 // We don't have a three-dimensional sparse model,
830 // so use a note model. We do have some logic (in
831 // extractStructure below) for guessing whether
832 // this should after all have been a dense model,
833 // but it's hard to apply it because we don't have
834 // all the necessary timing data yet... hmm
835
836 model = new NoteModel(m_sampleRate, 1, false);
837 }
838 }
839
840 model->setRDFTypeURI(type);
841
842 if (m_audioModelMap.find(source) != m_audioModelMap.end()) {
843 std::cerr << "source model for " << model << " is " << m_audioModelMap[source] << std::endl;
844 model->setSourceModel(m_audioModelMap[source]);
845 }
846
847 QString titleQuery = QString
848 (
849 " PREFIX dc: <http://purl.org/dc/elements/1.1/> "
850 " SELECT ?title "
851 " FROM <%1> "
852 " WHERE { "
853 " <%2> dc:title ?title . "
854 " } "
855 ).arg(m_uristring).arg(type);
856 QString title = SimpleSPARQLQuery::singleResultQuery
857 (s, titleQuery, "title").value;
858 if (title == "") {
859 // take it from the end of the event type
860 title = type;
861 title.replace(QRegExp("^.*[/#]"), "");
862 }
863 model->setObjectName(title);
864
865 modelMap[timeline][type][dimensions][haveDuration] = model;
866 models.push_back(model);
867 }
868
869 model = modelMap[timeline][type][dimensions][haveDuration];
870
871 if (model) {
872 long ftime = RealTime::realTime2Frame(time, m_sampleRate);
873 long fduration = RealTime::realTime2Frame(duration, m_sampleRate);
874 fillModel(model, ftime, fduration, haveDuration, values, label);
875 } 697 }
876 } 698 }
877 } 699 }
878 700
879 void 701 void
882 long fduration, 704 long fduration,
883 bool haveDuration, 705 bool haveDuration,
884 std::vector<float> &values, 706 std::vector<float> &values,
885 QString label) 707 QString label)
886 { 708 {
887 // std::cerr << "RDFImporterImpl::fillModel: adding point at frame " << ftime << std::endl; 709 // SVDEBUG << "RDFImporterImpl::fillModel: adding point at frame " << ftime << endl;
888 710
889 SparseOneDimensionalModel *sodm = 711 SparseOneDimensionalModel *sodm =
890 dynamic_cast<SparseOneDimensionalModel *>(model); 712 dynamic_cast<SparseOneDimensionalModel *>(model);
891 if (sodm) { 713 if (sodm) {
892 SparseOneDimensionalModel::Point point(ftime, label); 714 SparseOneDimensionalModel::Point point(ftime, label);
983 RDFImporter::RDFDocumentType 805 RDFImporter::RDFDocumentType
984 RDFImporter::identifyDocumentType(QString url) 806 RDFImporter::identifyDocumentType(QString url)
985 { 807 {
986 bool haveAudio = false; 808 bool haveAudio = false;
987 bool haveAnnotations = false; 809 bool haveAnnotations = false;
988 810 bool haveRDF = false;
989 // This query is not expected to return any values, but if it 811
990 // executes successfully (leaving no error in the error string) 812 BasicStore *store = 0;
991 // then we know we have RDF 813
992 SimpleSPARQLQuery q(SimpleSPARQLQuery::QueryFromSingleSource, 814 // This is not expected to return anything useful, but if it does
993 QString(" SELECT ?x FROM <%1> WHERE { ?x <y> <z> } ") 815 // anything at all then we know we have RDF
994 .arg(url)); 816 try {
995 817 //!!! non-local document?
996 SimpleSPARQLQuery::ResultList r = q.execute(); 818 store = BasicStore::load(QUrl(url));
997 if (!q.isOK()) { 819 Triple t = store->matchOnce(Triple());
998 SimpleSPARQLQuery::closeSingleSource(url); 820 if (t != Triple()) haveRDF = true;
821 } catch (std::exception &e) {
822 // nothing; haveRDF will be false so the next bit catches it
823 }
824
825 if (!haveRDF) {
826 delete store;
999 return NotRDF; 827 return NotRDF;
1000 } 828 }
1001 829
830 store->addPrefix("mo", Uri("http://purl.org/ontology/mo/"));
831 store->addPrefix("event", Uri("http://purl.org/NET/c4dm/event.owl#"));
832 store->addPrefix("af", Uri("http://purl.org/ontology/af/"));
833
1002 // "MO-conformant" structure for audio files 834 // "MO-conformant" structure for audio files
1003 835
1004 SimpleSPARQLQuery::Value value = 836 Node n = store->complete(Triple(Node(), Uri("a"), store->expand("mo:AudioFile")));
1005 SimpleSPARQLQuery::singleResultQuery 837 if (n != Node() && n.type == Node::URI) {
1006 (SimpleSPARQLQuery::QueryFromSingleSource,
1007 QString
1008 (" PREFIX mo: <http://purl.org/ontology/mo/> "
1009 " SELECT ?url FROM <%1> "
1010 " WHERE { ?url a mo:AudioFile } "
1011 ).arg(url),
1012 "url");
1013
1014 if (value.type == SimpleSPARQLQuery::URIValue) {
1015 838
1016 haveAudio = true; 839 haveAudio = true;
1017 840
1018 } else { 841 } else {
1019 842
1020 // Sonic Annotator v0.2 and below used to write this structure 843 // Sonic Annotator v0.2 and below used to write this structure
1021 // (which is not properly in conformance with the Music 844 // (which is not properly in conformance with the Music
1022 // Ontology) 845 // Ontology)
1023 846
1024 value = 847 Nodes sigs = store->match(Triple(Node(), Uri("a"), store->expand("mo:Signal"))).subjects();
1025 SimpleSPARQLQuery::singleResultQuery 848 foreach (Node sig, sigs) {
1026 (SimpleSPARQLQuery::QueryFromSingleSource, 849 Node aa = store->complete(Triple(sig, store->expand("mo:available_as"), Node()));
1027 QString 850 if (aa != Node()) {
1028 (" PREFIX mo: <http://purl.org/ontology/mo/> " 851 haveAudio = true;
1029 " SELECT ?url FROM <%1> " 852 break;
1030 " WHERE { ?signal a mo:Signal ; mo:available_as ?url } " 853 }
1031 ).arg(url), 854 }
1032 "url"); 855 }
1033 856
1034 if (value.type == SimpleSPARQLQuery::URIValue) { 857 SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAudio = "
1035 haveAudio = true; 858 << haveAudio << endl;
1036 } 859
1037 } 860 // can't call complete() with two Nothing nodes
1038 861 n = store->matchOnce(Triple(Node(), store->expand("event:time"), Node())).c;
1039 std::cerr << "NOTE: RDFImporter::identifyDocumentType: haveAudio = " 862 if (n != Node()) {
1040 << haveAudio << std::endl;
1041
1042 value =
1043 SimpleSPARQLQuery::singleResultQuery
1044 (SimpleSPARQLQuery::QueryFromSingleSource,
1045 QString
1046 (" PREFIX event: <http://purl.org/NET/c4dm/event.owl#> "
1047 " SELECT ?thing FROM <%1> "
1048 " WHERE { ?thing event:time ?time } "
1049 ).arg(url),
1050 "thing");
1051
1052 if (value.type == SimpleSPARQLQuery::URIValue) {
1053 haveAnnotations = true; 863 haveAnnotations = true;
1054 } 864 }
1055 865
1056 if (!haveAnnotations) { 866 if (!haveAnnotations) {
1057 867 // can't call complete() with two Nothing nodes
1058 value = 868 n = store->matchOnce(Triple(Node(), store->expand("af:signal_feature"), Node())).c;
1059 SimpleSPARQLQuery::singleResultQuery 869 if (n != Node()) {
1060 (SimpleSPARQLQuery::QueryFromSingleSource,
1061 QString
1062 (" PREFIX af: <http://purl.org/ontology/af/> "
1063 " SELECT ?thing FROM <%1> "
1064 " WHERE { ?signal af:signal_feature ?thing } "
1065 ).arg(url),
1066 "thing");
1067
1068 if (value.type == SimpleSPARQLQuery::URIValue) {
1069 haveAnnotations = true; 870 haveAnnotations = true;
1070 } 871 }
1071 } 872 }
1072 873
1073 std::cerr << "NOTE: RDFImporter::identifyDocumentType: haveAnnotations = " 874 SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAnnotations = "
1074 << haveAnnotations << std::endl; 875 << haveAnnotations << endl;
1075 876
1076 SimpleSPARQLQuery::closeSingleSource(url); 877 delete store;
1077 878
1078 if (haveAudio) { 879 if (haveAudio) {
1079 if (haveAnnotations) { 880 if (haveAnnotations) {
1080 return AudioRefAndAnnotations; 881 return AudioRefAndAnnotations;
1081 } else { 882 } else {
1090 } 891 }
1091 892
1092 return OtherRDFDocument; 893 return OtherRDFDocument;
1093 } 894 }
1094 895
1095 void
1096 RDFImporterImpl::loadPrefixes(ProgressReporter *reporter)
1097 {
1098 return;
1099 //!!!
1100 if (m_prefixesLoaded) return;
1101 const char *prefixes[] = {
1102 "http://purl.org/NET/c4dm/event.owl",
1103 "http://purl.org/NET/c4dm/timeline.owl",
1104 "http://purl.org/ontology/mo/",
1105 "http://purl.org/ontology/af/",
1106 "http://www.w3.org/2000/01/rdf-schema",
1107 "http://purl.org/dc/elements/1.1/",
1108 };
1109 for (size_t i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); ++i) {
1110 CachedFile cf(prefixes[i], reporter, "application/rdf+xml");
1111 if (!cf.isOK()) continue;
1112 SimpleSPARQLQuery::addSourceToModel
1113 (QUrl::fromLocalFile(cf.getLocalFilename()).toString());
1114 }
1115 m_prefixesLoaded = true;
1116 }