RDFImporter.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2008-2012 QMUL.
8 
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
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "RDFImporter.h"
17 
18 #include <map>
19 #include <vector>
20 
21 #include <iostream>
22 #include <cmath>
23 
24 #include "base/ProgressReporter.h"
25 #include "base/RealTime.h"
26 #include "base/StringBits.h"
27 
31 #include "data/model/NoteModel.h"
32 #include "data/model/TextModel.h"
33 #include "data/model/RegionModel.h"
35 
36 #include "data/fileio/FileSource.h"
37 #include "data/fileio/CachedFile.h"
38 #include "data/fileio/FileFinder.h"
39 #include "data/fileio/TextTest.h"
40 
41 #include <dataquay/BasicStore.h>
42 #include <dataquay/PropertyObject.h>
43 
44 using Dataquay::Uri;
45 using Dataquay::Node;
46 using Dataquay::Nodes;
47 using Dataquay::Triple;
48 using Dataquay::Triples;
49 using Dataquay::BasicStore;
50 using Dataquay::PropertyObject;
51 
53 {
54 public:
55  RDFImporterImpl(QString url, sv_samplerate_t sampleRate);
56  virtual ~RDFImporterImpl();
57 
58  void setSampleRate(sv_samplerate_t sampleRate) { m_sampleRate = sampleRate; }
59 
60  bool isOK();
61  QString getErrorString() const;
62 
63  std::vector<ModelId> getDataModels(ProgressReporter *);
64 
65 protected:
66  BasicStore *m_store;
67  Uri expand(QString s) { return m_store->expand(s); }
68 
69  QString m_uristring;
70  QString m_errorString;
71  std::map<QString, ModelId> m_audioModelMap;
73 
74  std::map<ModelId, std::map<QString, float> > m_labelValueMap;
75 
76  void getDataModelsAudio(std::vector<ModelId> &, ProgressReporter *);
77  void getDataModelsSparse(std::vector<ModelId> &, ProgressReporter *);
78  void getDataModelsDense(std::vector<ModelId> &, ProgressReporter *);
79 
80  QString getDenseModelTitle(QString featureUri, QString featureTypeUri);
81 
82  void getDenseFeatureProperties(QString featureUri,
83  sv_samplerate_t &sampleRate, int &windowLength,
84  int &hopSize, int &width, int &height);
85 
87  bool, std::vector<float> &, QString);
88 };
89 
90 QString
92 {
93  return "*.rdf *.n3 *.ttl";
94 }
95 
96 RDFImporter::RDFImporter(QString url, sv_samplerate_t sampleRate) :
97  m_d(new RDFImporterImpl(url, sampleRate))
98 {
99 }
100 
102 {
103  delete m_d;
104 }
105 
106 void
108 {
109  m_d->setSampleRate(sampleRate);
110 }
111 
112 bool
114 {
115  return m_d->isOK();
116 }
117 
118 QString
120 {
121  return m_d->getErrorString();
122 }
123 
124 std::vector<ModelId>
126 {
127  return m_d->getDataModels(r);
128 }
129 
131  m_store(new BasicStore),
132  m_uristring(uri),
133  m_sampleRate(sampleRate)
134 {
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  }
155 }
156 
158 {
159  delete m_store;
160 }
161 
162 bool
164 {
165  return (m_errorString == "");
166 }
167 
168 QString
170 {
171  return m_errorString;
172 }
173 
174 std::vector<ModelId>
176 {
177  std::vector<ModelId> models;
178 
179  getDataModelsAudio(models, reporter);
180 
181  if (m_sampleRate == 0) {
182  m_errorString = QString("Invalid audio data model (is audio file format supported?)");
183  cerr << m_errorString << endl;
184  return models;
185  }
186 
187  QString error;
188 
189  if (m_errorString != "") {
190  error = m_errorString;
191  }
192  m_errorString = "";
193 
194  getDataModelsDense(models, reporter);
195 
196  if (m_errorString != "") {
197  error = m_errorString;
198  }
199  m_errorString = "";
200 
201  getDataModelsSparse(models, reporter);
202 
203  if (m_errorString == "" && error != "") {
204  m_errorString = error;
205  }
206 
207  return models;
208 }
209 
210 void
211 RDFImporterImpl::getDataModelsAudio(std::vector<ModelId> &models,
212  ProgressReporter *reporter)
213 {
214  Nodes sigs = m_store->match
215  (Triple(Node(), Uri("a"), expand("mo:Signal"))).subjects();
216 
217  foreach (Node sig, sigs) {
218 
219  Node file = m_store->complete(Triple(Node(), expand("mo:encodes"), sig));
220  if (file == Node()) {
221  file = m_store->complete(Triple(sig, expand("mo:available_as"), Node()));
222  }
223  if (file == Node()) {
224  cerr << "RDFImporterImpl::getDataModelsAudio: ERROR: No source for signal " << sig << endl;
225  continue;
226  }
227 
228  QString signal = sig.value;
229  QString source = file.value;
230 
231  SVDEBUG << "NOTE: Seeking signal source \"" << source
232  << "\"..." << endl;
233 
234  FileSource *fs = new FileSource(source, reporter);
235  if (fs->isAvailable()) {
236  SVDEBUG << "NOTE: Source is available: Local filename is \""
237  << fs->getLocalFilename()
238  << "\"..." << endl;
239  }
240 
241 #ifdef NO_SV_GUI
242  if (!fs->isAvailable()) {
243  m_errorString = QString("Signal source \"%1\" is not available").arg(source);
244  delete fs;
245  continue;
246  }
247 #else
248  if (!fs->isAvailable()) {
249  SVDEBUG << "NOTE: Signal source \"" << source
250  << "\" is not available, using file finder..." << endl;
252  if (ff) {
253  QString path = ff->find(FileFinder::AudioFile,
254  fs->getLocation(),
255  m_uristring);
256  if (path != "") {
257  cerr << "File finder returns: \"" << path
258  << "\"" << endl;
259  delete fs;
260  fs = new FileSource(path, reporter);
261  if (!fs->isAvailable()) {
262  delete fs;
263  m_errorString = QString("Signal source \"%1\" is not available").arg(source);
264  continue;
265  }
266  }
267  }
268  }
269 #endif
270 
271  if (reporter) {
272  reporter->setMessage(RDFImporter::tr("Importing audio referenced in RDF..."));
273  }
274  fs->waitForData();
275  auto newModel = std::make_shared<ReadOnlyWaveFileModel>
276  (*fs, m_sampleRate);
277  if (newModel->isOK()) {
278  cerr << "Successfully created wave file model from source at \"" << source << "\"" << endl;
279  auto modelId = ModelById::add(newModel);
280  models.push_back(modelId);
281  m_audioModelMap[signal] = modelId;
282  if (m_sampleRate == 0) {
283  m_sampleRate = newModel->getSampleRate();
284  }
285  } else {
286  m_errorString = QString("Failed to create wave file model from source at \"%1\"").arg(source);
287  }
288  delete fs;
289  }
290 }
291 
292 void
293 RDFImporterImpl::getDataModelsDense(std::vector<ModelId> &models,
294  ProgressReporter *reporter)
295 {
296  if (reporter) {
297  reporter->setMessage(RDFImporter::tr("Importing dense signal data from RDF..."));
298  }
299 
300  Nodes sigFeatures = m_store->match
301  (Triple(Node(), expand("af:signal_feature"), Node())).objects();
302 
303  foreach (Node sf, sigFeatures) {
304 
305  if (sf.type != Node::URI && sf.type != Node::Blank) continue;
306 
307  Node t = m_store->complete(Triple(sf, expand("a"), Node()));
308  Node v = m_store->complete(Triple(sf, expand("af:value"), Node()));
309 
310  QString feature = sf.value;
311  QString type = t.value;
312  QString value = v.value;
313 
314  if (type == "" || value == "") continue;
315 
316  sv_samplerate_t sampleRate = 0;
317  int windowLength = 0;
318  int hopSize = 0;
319  int width = 0;
320  int height = 0;
322  (feature, sampleRate, windowLength, hopSize, width, height);
323 
324  if (sampleRate != 0 && sampleRate != m_sampleRate) {
325  cerr << "WARNING: Sample rate in dense feature description does not match our underlying rate -- using rate from feature description" << endl;
326  }
327  if (sampleRate == 0) sampleRate = m_sampleRate;
328 
329  if (hopSize == 0) {
330  cerr << "WARNING: Dense feature description does not specify a hop size -- assuming 1" << endl;
331  hopSize = 1;
332  }
333 
334  if (height == 0) {
335  cerr << "WARNING: Dense feature description does not specify feature signal dimensions -- assuming one-dimensional (height = 1)" << endl;
336  height = 1;
337  }
338 
339  QStringList values = value.split(' ', QString::SkipEmptyParts);
340 
341  if (values.empty()) {
342  cerr << "WARNING: Dense feature description does not specify any values!" << endl;
343  continue;
344  }
345 
346  if (height == 1) {
347 
348  auto m = std::make_shared<SparseTimeValueModel>
349  (sampleRate, hopSize, false);
350 
351  for (int j = 0; j < values.size(); ++j) {
352  float f = values[j].toFloat();
353  Event e(j * hopSize, f, "");
354  m->add(e);
355  }
356 
357  m->setObjectName(getDenseModelTitle(feature, type));
358  m->setRDFTypeURI(type);
359  models.push_back(ModelById::add(m));
360 
361  } else {
362 
363  auto m = std::make_shared<EditableDenseThreeDimensionalModel>
364  (sampleRate, hopSize, height, false);
365 
367 
368  int x = 0;
369 
370  for (int j = 0; j < values.size(); ++j) {
371  if (j % height == 0 && !column.empty()) {
372  m->setColumn(x++, column);
373  column.clear();
374  }
375  column.push_back(values[j].toFloat());
376  }
377 
378  if (!column.empty()) {
379  m->setColumn(x++, column);
380  }
381 
382  m->setObjectName(getDenseModelTitle(feature, type));
383  m->setRDFTypeURI(type);
384  models.push_back(ModelById::add(m));
385  }
386  }
387 }
388 
389 QString
391  QString featureTypeUri)
392 {
393  Node n = m_store->complete
394  (Triple(Uri(featureUri), expand("dc:title"), Node()));
395 
396  if (n.type == Node::Literal && n.value != "") {
397  SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal) \"" << n.value << "\"" << endl;
398  return n.value;
399  }
400 
401  n = m_store->complete
402  (Triple(Uri(featureTypeUri), expand("dc:title"), Node()));
403 
404  if (n.type == Node::Literal && n.value != "") {
405  SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal type) \"" << n.value << "\"" << endl;
406  return n.value;
407  }
408 
409  SVDEBUG << "RDFImporterImpl::getDenseModelTitle: No title available for feature <" << featureUri << ">" << endl;
410  return {};
411 }
412 
413 void
415  sv_samplerate_t &sampleRate, int &windowLength,
416  int &hopSize, int &width, int &height)
417 {
418  Node dim = m_store->complete
419  (Triple(Uri(featureUri), expand("af:dimensions"), Node()));
420 
421  cerr << "Dimensions = \"" << dim.value << "\"" << endl;
422 
423  if (dim.type == Node::Literal && dim.value != "") {
424  QStringList dl = dim.value.split(" ");
425  if (dl.empty()) dl.push_back(dim.value);
426  if (dl.size() > 0) height = dl[0].toInt();
427  if (dl.size() > 1) width = dl[1].toInt();
428  }
429 
430  // Looking for rate, hop, window from:
431  //
432  // ?feature mo:time ?time .
433  // ?time a tl:Interval .
434  // ?time tl:onTimeLine ?timeline .
435  // ?map tl:rangeTimeLine ?timeline .
436  // ?map tl:sampleRate ?rate .
437  // ?map tl:hopSize ?hop .
438  // ?map tl:windowLength ?window .
439 
440  Node interval = m_store->complete(Triple(Uri(featureUri), expand("mo:time"), Node()));
441 
442  if (!m_store->contains(Triple(interval, expand("a"), expand("tl:Interval")))) {
443  cerr << "RDFImporterImpl::getDenseFeatureProperties: Feature time node "
444  << interval << " is not a tl:Interval" << endl;
445  return;
446  }
447 
448  Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
449 
450  if (tl == Node()) {
451  cerr << "RDFImporterImpl::getDenseFeatureProperties: Interval node "
452  << interval << " lacks tl:onTimeLine property" << endl;
453  return;
454  }
455 
456  Node map = m_store->complete(Triple(Node(), expand("tl:rangeTimeLine"), tl));
457 
458  if (map == Node()) {
459  cerr << "RDFImporterImpl::getDenseFeatureProperties: No map for "
460  << "timeline node " << tl << endl;
461  }
462 
463  PropertyObject po(m_store, "tl:", map);
464 
465  if (po.hasProperty("sampleRate")) {
466  sampleRate = po.getProperty("sampleRate").toDouble();
467  }
468  if (po.hasProperty("hopSize")) {
469  hopSize = po.getProperty("hopSize").toInt();
470  }
471  if (po.hasProperty("windowLength")) {
472  windowLength = po.getProperty("windowLength").toInt();
473  }
474 
475  cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl;
476 }
477 
478 void
479 RDFImporterImpl::getDataModelsSparse(std::vector<ModelId> &models,
480  ProgressReporter *reporter)
481 {
482  if (reporter) {
483  reporter->setMessage(RDFImporter::tr("Importing event data from RDF..."));
484  }
485 
486  /*
487  This function is only used for sparse data (for dense data we
488  would be in getDataModelsDense instead).
489 
490  Our query is intended to retrieve every thing that has a time,
491  and every feature type and value associated with a thing that
492  has a time.
493 
494  We will then need to refine this big bag of results into a set
495  of data models.
496 
497  Results that have different source signals should go into
498  different models.
499 
500  Results that have different feature types should go into
501  different models.
502  */
503 
504  Nodes sigs = m_store->match
505  (Triple(Node(), expand("a"), expand("mo:Signal"))).subjects();
506 
507  // Map from timeline uri to event type to dimensionality to
508  // presence of duration to model id. Whee!
509  std::map<QString, std::map<QString, std::map<int, std::map<bool, ModelId> > > >
510  modelMap;
511 
512  foreach (Node sig, sigs) {
513 
514  Node interval = m_store->complete(Triple(sig, expand("mo:time"), Node()));
515  if (interval == Node()) continue;
516 
517  Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
518  if (tl == Node()) continue;
519 
520  Nodes times = m_store->match(Triple(Node(), expand("tl:onTimeLine"), tl)).subjects();
521 
522  foreach (Node tn, times) {
523 
524  Nodes timedThings = m_store->match(Triple(Node(), expand("event:time"), tn)).subjects();
525 
526  foreach (Node thing, timedThings) {
527 
528  Node typ = m_store->complete(Triple(thing, expand("a"), Node()));
529  if (typ == Node()) continue;
530 
531  Node valu = m_store->complete(Triple(thing, expand("af:feature"), Node()));
532 
533  QString source = sig.value;
534  QString timeline = tl.value;
535  QString type = typ.value;
536  QString thinguri = thing.value;
537 
538  /*
539  For sparse data, the determining factors in deciding
540  what model to use are: Do the features have values?
541  and Do the features have duration?
542 
543  We can run through the results and check off whether
544  we find values and duration for each of the
545  source+type keys, and then run through the
546  source+type keys pushing each of the results into a
547  suitable model.
548 
549  Unfortunately, at this point we do not yet have any
550  actual timing data (time/duration) -- just the time
551  URI.
552 
553  What we _could_ do is to create one of each type of
554  model at the start, for each of the source+type
555  keys, and then push each feature into the relevant
556  model depending on what we find out about it. Then
557  return only non-empty models.
558  */
559 
560  QString label = "";
561  bool text = (type.contains("Text") || type.contains("text")); // Ha, ha
562  bool note = (type.contains("Note") || type.contains("note")); // Guffaw
563 
564  if (text) {
565  label = m_store->complete(Triple(thing, expand("af:text"), Node())).value;
566  }
567 
568  if (label == "") {
569  label = m_store->complete(Triple(thing, expand("rdfs:label"), Node())).value;
570  }
571 
572  RealTime time;
573  RealTime duration;
574 
575 // bool haveTime = false;
576  bool haveDuration = false;
577 
578  Node at = m_store->complete(Triple(tn, expand("tl:at"), Node()));
579 
580  if (at != Node()) {
581  time = RealTime::fromXsdDuration(at.value.toStdString());
582 // haveTime = true;
583  } else {
585  // beginsAt -> start
586  // onTimeLine -> timeline
587 
588  Node start = m_store->complete(Triple(tn, expand("tl:beginsAt"), Node()));
589  Node dur = m_store->complete(Triple(tn, expand("tl:duration"), Node()));
590  if (start != Node() && dur != Node()) {
592  (start.value.toStdString());
593  duration = RealTime::fromXsdDuration
594  (dur.value.toStdString());
595 // haveTime = haveDuration = true;
596  }
597  }
598 
599  QString valuestring = valu.value;
600  std::vector<float> values;
601 
602  if (valuestring != "") {
603  QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts);
604  for (int j = 0; j < vsl.size(); ++j) {
605  bool success = false;
606  float v = vsl[j].toFloat(&success);
607  if (success) values.push_back(v);
608  }
609  }
610 
611  int dimensions = 1;
612  if (values.size() == 1) dimensions = 2;
613  else if (values.size() > 1) dimensions = 3;
614 
615  ModelId modelId;
616 
617  if (modelMap[timeline][type][dimensions].find(haveDuration) ==
618  modelMap[timeline][type][dimensions].end()) {
619 
620 /*
621  SVDEBUG << "Creating new model: source = " << source << ", type = " << type << ", dimensions = "
622  << dimensions << ", haveDuration = " << haveDuration
623  << ", time = " << time << ", duration = " << duration
624  << endl;
625 */
626 
627  Model *model = nullptr;
628 
629  if (!haveDuration) {
630 
631  if (dimensions == 1) {
632  if (text) {
633  model = new TextModel(m_sampleRate, 1, false);
634  } else {
635  model = new SparseOneDimensionalModel(m_sampleRate, 1, false);
636  }
637  } else if (dimensions == 2) {
638  if (text) {
639  model = new TextModel(m_sampleRate, 1, false);
640  } else {
641  model = new SparseTimeValueModel(m_sampleRate, 1, false);
642  }
643  } else {
644  // We don't have a three-dimensional sparse model,
645  // so use a note model. We do have some logic (in
646  // extractStructure below) for guessing whether
647  // this should after all have been a dense model,
648  // but it's hard to apply it because we don't have
649  // all the necessary timing data yet... hmm
650  model = new NoteModel(m_sampleRate, 1, false);
651  }
652 
653  } else { // haveDuration
654 
655  if (note || (dimensions > 2)) {
656  model = new NoteModel(m_sampleRate, 1, false);
657  } else {
658  // If our units are frequency or midi pitch, we
659  // should be using a note model... hm
660  model = new RegionModel(m_sampleRate, 1, false);
661  }
662  }
663 
664  model->setRDFTypeURI(type);
665 
666  if (m_audioModelMap.find(source) != m_audioModelMap.end()) {
667  cerr << "source model for " << model << " is " << m_audioModelMap[source] << endl;
668  model->setSourceModel(m_audioModelMap[source]);
669  }
670 
671  QString title = m_store->complete
672  (Triple(typ, expand("dc:title"), Node())).value;
673  if (title == "") {
674  // take it from the end of the event type
675  title = type;
676  title.replace(QRegExp("^.*[/#]"), "");
677  }
678  model->setObjectName(title);
679 
680  modelId = ModelById::add(std::shared_ptr<Model>(model));
681  modelMap[timeline][type][dimensions][haveDuration] = modelId;
682  models.push_back(modelId);
683  }
684 
685  modelId = modelMap[timeline][type][dimensions][haveDuration];
686 
687  if (!modelId.isNone()) {
688  sv_frame_t ftime =
690  sv_frame_t fduration =
692  fillModel(modelId, ftime, fduration,
693  haveDuration, values, label);
694  }
695  }
696  }
697  }
698 }
699 
700 void
702  sv_frame_t ftime,
703  sv_frame_t fduration,
704  bool haveDuration,
705  std::vector<float> &values,
706  QString label)
707 {
708 // SVDEBUG << "RDFImporterImpl::fillModel: adding point at frame " << ftime << endl;
709 
710  if (auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId)) {
711  Event point(ftime, label);
712  sodm->add(point);
713  return;
714  }
715 
716  if (auto tm = ModelById::getAs<TextModel>(modelId)) {
717  Event e
718  (ftime,
719  values.empty() ? 0.5f : values[0] < 0.f ? 0.f : values[0] > 1.f ? 1.f : values[0], // I was young and feckless once too
720  label);
721  tm->add(e);
722  return;
723  }
724 
725  if (auto stvm = ModelById::getAs<SparseTimeValueModel>(modelId)) {
726  Event e(ftime, values.empty() ? 0.f : values[0], label);
727  stvm->add(e);
728  return;
729  }
730 
731  if (auto nm = ModelById::getAs<NoteModel>(modelId)) {
732  if (haveDuration) {
733  float value = 0.f, level = 1.f;
734  if (!values.empty()) {
735  value = values[0];
736  if (values.size() > 1) {
737  level = values[1];
738  }
739  }
740  Event e(ftime, value, fduration, level, label);
741  nm->add(e);
742  } else {
743  float value = 0.f, duration = 1.f, level = 1.f;
744  if (!values.empty()) {
745  value = values[0];
746  if (values.size() > 1) {
747  duration = values[1];
748  if (values.size() > 2) {
749  level = values[2];
750  }
751  }
752  }
753  Event e(ftime, value, sv_frame_t(lrintf(duration)),
754  level, label);
755  nm->add(e);
756  }
757  return;
758  }
759 
760  if (auto rm = ModelById::getAs<RegionModel>(modelId)) {
761  float value = 0.f;
762  if (values.empty()) {
763  // no values? map each unique label to a distinct value
764  if (m_labelValueMap[modelId].find(label) == m_labelValueMap[modelId].end()) {
765  m_labelValueMap[modelId][label] = rm->getValueMaximum() + 1.f;
766  }
767  value = m_labelValueMap[modelId][label];
768  } else {
769  value = values[0];
770  }
771  if (haveDuration) {
772  Event e(ftime, value, fduration, label);
773  rm->add(e);
774  } else {
775  // This won't actually happen -- we only create region models
776  // if we do have duration -- but just for completeness
777  float duration = 1.f;
778  if (!values.empty()) {
779  value = values[0];
780  if (values.size() > 1) {
781  duration = values[1];
782  }
783  }
784  Event e(ftime, value, sv_frame_t(lrintf(duration)), label);
785  rm->add(e);
786  }
787  return;
788  }
789 
790  cerr << "WARNING: RDFImporterImpl::fillModel: Unknown or unexpected model type" << endl;
791  return;
792 }
793 
796 {
797  bool haveAudio = false;
798  bool haveAnnotations = false;
799  bool haveRDF = false;
800 
801  if (!isPlausibleDocumentOfAnyKind(url)) {
802  return NotRDF;
803  }
804 
805  BasicStore *store = nullptr;
806 
807  // This is not expected to return anything useful, but if it does
808  // anything at all then we know we have RDF
809  try {
810  store = BasicStore::load(url);
811  Triple t = store->matchOnce(Triple());
812  if (t != Triple()) haveRDF = true;
813  } catch (std::exception &) {
814  // nothing; haveRDF will be false so the next bit catches it
815  }
816 
817  if (!haveRDF) {
818  delete store;
819  return NotRDF;
820  }
821 
822  store->addPrefix("mo", Uri("http://purl.org/ontology/mo/"));
823  store->addPrefix("event", Uri("http://purl.org/NET/c4dm/event.owl#"));
824  store->addPrefix("af", Uri("http://purl.org/ontology/af/"));
825 
826  // "MO-conformant" structure for audio files
827 
828  Node n = store->complete(Triple(Node(), Uri("a"), store->expand("mo:AudioFile")));
829  if (n != Node() && n.type == Node::URI) {
830 
831  haveAudio = true;
832 
833  } else {
834 
835  // Sonic Annotator v0.2 and below used to write this structure
836  // (which is not properly in conformance with the Music
837  // Ontology)
838 
839  Nodes sigs = store->match(Triple(Node(), Uri("a"), store->expand("mo:Signal"))).subjects();
840  foreach (Node sig, sigs) {
841  Node aa = store->complete(Triple(sig, store->expand("mo:available_as"), Node()));
842  if (aa != Node()) {
843  haveAudio = true;
844  break;
845  }
846  }
847  }
848 
849  SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAudio = "
850  << haveAudio << endl;
851 
852  // can't call complete() with two Nothing nodes
853  n = store->matchOnce(Triple(Node(), store->expand("event:time"), Node())).c;
854  if (n != Node()) {
855  haveAnnotations = true;
856  }
857 
858  if (!haveAnnotations) {
859  // can't call complete() with two Nothing nodes
860  n = store->matchOnce(Triple(Node(), store->expand("af:signal_feature"), Node())).c;
861  if (n != Node()) {
862  haveAnnotations = true;
863  }
864  }
865 
866  SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAnnotations = "
867  << haveAnnotations << endl;
868 
869  delete store;
870 
871  if (haveAudio) {
872  if (haveAnnotations) {
873  return AudioRefAndAnnotations;
874  } else {
875  return AudioRef;
876  }
877  } else {
878  if (haveAnnotations) {
879  return Annotations;
880  } else {
881  return OtherRDFDocument;
882  }
883  }
884 
885  return OtherRDFDocument;
886 }
887 
888 bool
890 {
892 }
893 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
bool isNone() const
Definition: ById.h:133
void getDataModelsSparse(std::vector< ModelId > &, ProgressReporter *)
std::map< QString, ModelId > m_audioModelMap
Definition: RDFImporter.cpp:71
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
QString getLocation() const
Return the location filename or URL as passed to the constructor.
Definition: FileSource.cpp:616
QString getErrorString() const
static FileFinder * getInstance()
Definition: FileFinder.h:54
static QString getKnownExtensions()
Return the file extensions that we have data file readers for, in a format suitable for use with QFil...
Definition: RDFImporter.cpp:91
QString getErrorString() const
virtual ~RDFImporter()
void setRDFTypeURI(QString uri)
Set the event, feature, or signal type URI for the features contained in this model, according to the Audio Features RDF ontology.
Definition: Model.h:264
static bool isPlausibleDocumentOfAnyKind(QUrl url)
QString getLocalFilename() const
Return the name of the local file this FileSource refers to.
Definition: FileSource.cpp:622
void setSampleRate(sv_samplerate_t sampleRate)
A model representing casual textual annotations.
Definition: TextModel.h:36
RDFImporterImpl(QString url, sv_samplerate_t sampleRate)
QString m_uristring
Definition: RDFImporter.cpp:69
void waitForData()
Block on a sub-event-loop until the whole of the data has been retrieved (if it is remote)...
Definition: FileSource.cpp:570
RDFImporterImpl * m_d
Definition: RDFImporter.h:70
static Id add(std::shared_ptr< Item > item)
Definition: ById.h:228
std::vector< ModelId > getDataModels(ProgressReporter *reporter)
Return a list of models imported from the RDF source.
void fillModel(ModelId, sv_frame_t, sv_frame_t, bool, std::vector< float > &, QString)
std::map< ModelId, std::map< QString, float > > m_labelValueMap
Definition: RDFImporter.cpp:74
void setSampleRate(sv_samplerate_t sampleRate)
Definition: RDFImporter.cpp:58
void getDataModelsAudio(std::vector< ModelId > &, ProgressReporter *)
Model is the base class for all data models that represent any sort of data on a time scale based on ...
Definition: Model.h:51
RDFImporter(QString url, sv_samplerate_t sampleRate=0)
Definition: RDFImporter.cpp:96
void getDenseFeatureProperties(QString featureUri, sv_samplerate_t &sampleRate, int &windowLength, int &hopSize, int &width, int &height)
static bool isApparentTextDocument(FileSource)
Return true if the source appears to point to a text format of some kind (could be CSV...
Definition: TextTest.cpp:24
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
Definition: FileSource.h:59
static sv_frame_t realTime2Frame(const RealTime &r, sv_samplerate_t sampleRate)
Convert a RealTime into a sample frame at the given sample rate.
Definition: RealTimeSV.cpp:490
virtual void setSourceModel(ModelId model)
Set the source model for this model.
Definition: Model.cpp:31
void getDataModelsDense(std::vector< ModelId > &, ProgressReporter *)
A model representing a wiggly-line plot with points at arbitrary intervals of the model resolution...
RegionModel – a model for intervals associated with a value, which we call regions for no very compe...
Definition: RegionModel.h:33
#define SVDEBUG
Definition: Debug.h:106
QString m_errorString
Definition: RDFImporter.cpp:70
Uri expand(QString s)
Definition: RDFImporter.cpp:67
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
static RDFDocumentType identifyDocumentType(QUrl url)
virtual ~RDFImporterImpl()
virtual QString find(FileType type, QString location, QString lastKnownLocation="")=0
virtual void setMessage(QString text)=0
A model representing a series of time instants with optional labels but without values.
BasicStore * m_store
Definition: RDFImporter.cpp:66
static RealTime fromXsdDuration(std::string xsdd)
Definition: RealTimeSV.cpp:96
Definition: ById.h:115
QString getDenseModelTitle(QString featureUri, QString featureTypeUri)
std::vector< ModelId > getDataModels(ProgressReporter *)
sv_samplerate_t m_sampleRate
Definition: RDFImporter.cpp:72
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
Definition: RealTime.h:42
bool isAvailable()
Return true if the file or remote URL exists.
Definition: FileSource.cpp:544