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