svcore  1.9
RDFImporter.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2008-2012 QMUL.
00008    
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "RDFImporter.h"
00017 
00018 #include <map>
00019 #include <vector>
00020 
00021 #include <iostream>
00022 #include <cmath>
00023 
00024 #include "base/ProgressReporter.h"
00025 #include "base/RealTime.h"
00026 
00027 #include "data/model/SparseOneDimensionalModel.h"
00028 #include "data/model/SparseTimeValueModel.h"
00029 #include "data/model/EditableDenseThreeDimensionalModel.h"
00030 #include "data/model/NoteModel.h"
00031 #include "data/model/TextModel.h"
00032 #include "data/model/RegionModel.h"
00033 #include "data/model/WaveFileModel.h"
00034 
00035 #include "data/fileio/FileSource.h"
00036 #include "data/fileio/CachedFile.h"
00037 #include "data/fileio/FileFinder.h"
00038 
00039 #include <dataquay/BasicStore.h>
00040 #include <dataquay/PropertyObject.h>
00041 
00042 using Dataquay::Uri;
00043 using Dataquay::Node;
00044 using Dataquay::Nodes;
00045 using Dataquay::Triple;
00046 using Dataquay::Triples;
00047 using Dataquay::BasicStore;
00048 using Dataquay::PropertyObject;
00049 
00050 class RDFImporterImpl
00051 {
00052 public:
00053     RDFImporterImpl(QString url, int sampleRate);
00054     virtual ~RDFImporterImpl();
00055 
00056     void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
00057     
00058     bool isOK();
00059     QString getErrorString() const;
00060 
00061     std::vector<Model *> getDataModels(ProgressReporter *);
00062 
00063 protected:
00064     BasicStore *m_store;
00065     Uri expand(QString s) { return m_store->expand(s); }
00066 
00067     QString m_uristring;
00068     QString m_errorString;
00069     std::map<QString, Model *> m_audioModelMap;
00070     int m_sampleRate;
00071 
00072     std::map<Model *, std::map<QString, float> > m_labelValueMap;
00073 
00074     void getDataModelsAudio(std::vector<Model *> &, ProgressReporter *);
00075     void getDataModelsSparse(std::vector<Model *> &, ProgressReporter *);
00076     void getDataModelsDense(std::vector<Model *> &, ProgressReporter *);
00077 
00078     void getDenseModelTitle(Model *, QString, QString);
00079 
00080     void getDenseFeatureProperties(QString featureUri,
00081                                    int &sampleRate, int &windowLength,
00082                                    int &hopSize, int &width, int &height);
00083 
00084     void fillModel(Model *, long, long, bool, std::vector<float> &, QString);
00085 };
00086 
00087 QString
00088 RDFImporter::getKnownExtensions()
00089 {
00090     return "*.rdf *.n3 *.ttl";
00091 }
00092 
00093 RDFImporter::RDFImporter(QString url, int sampleRate) :
00094     m_d(new RDFImporterImpl(url, sampleRate)) 
00095 {
00096 }
00097 
00098 RDFImporter::~RDFImporter()
00099 {
00100     delete m_d;
00101 }
00102 
00103 void
00104 RDFImporter::setSampleRate(int sampleRate)
00105 {
00106     m_d->setSampleRate(sampleRate);
00107 }
00108 
00109 bool
00110 RDFImporter::isOK()
00111 {
00112     return m_d->isOK();
00113 }
00114 
00115 QString
00116 RDFImporter::getErrorString() const
00117 {
00118     return m_d->getErrorString();
00119 }
00120 
00121 std::vector<Model *>
00122 RDFImporter::getDataModels(ProgressReporter *r)
00123 {
00124     return m_d->getDataModels(r);
00125 }
00126 
00127 RDFImporterImpl::RDFImporterImpl(QString uri, int sampleRate) :
00128     m_store(new BasicStore),
00129     m_uristring(uri),
00130     m_sampleRate(sampleRate)
00131 {
00133 
00134     m_store->addPrefix("mo", Uri("http://purl.org/ontology/mo/"));
00135     m_store->addPrefix("af", Uri("http://purl.org/ontology/af/"));
00136     m_store->addPrefix("dc", Uri("http://purl.org/dc/elements/1.1/"));
00137     m_store->addPrefix("tl", Uri("http://purl.org/NET/c4dm/timeline.owl#"));
00138     m_store->addPrefix("event", Uri("http://purl.org/NET/c4dm/event.owl#"));
00139     m_store->addPrefix("rdfs", Uri("http://www.w3.org/2000/01/rdf-schema#"));
00140 
00141     try {
00142         QUrl url;
00143         if (uri.startsWith("file:")) {
00144             url = QUrl(uri);
00145         } else {
00146             url = QUrl::fromLocalFile(uri);
00147         }
00148         m_store->import(url, BasicStore::ImportIgnoreDuplicates);
00149     } catch (std::exception &e) {
00150         m_errorString = e.what();
00151     }
00152 }
00153 
00154 RDFImporterImpl::~RDFImporterImpl()
00155 {
00156     delete m_store;
00157 }
00158 
00159 bool
00160 RDFImporterImpl::isOK()
00161 {
00162     return (m_errorString == "");
00163 }
00164 
00165 QString
00166 RDFImporterImpl::getErrorString() const
00167 {
00168     return m_errorString;
00169 }
00170 
00171 std::vector<Model *>
00172 RDFImporterImpl::getDataModels(ProgressReporter *reporter)
00173 {
00174     std::vector<Model *> models;
00175 
00176     getDataModelsAudio(models, reporter);
00177 
00178     if (m_sampleRate == 0) {
00179         m_errorString = QString("Invalid audio data model (is audio file format supported?)");
00180         cerr << m_errorString << endl;
00181         return models;
00182     }
00183 
00184     QString error;
00185 
00186     if (m_errorString != "") {
00187         error = m_errorString;
00188     }
00189     m_errorString = "";
00190 
00191     getDataModelsDense(models, reporter);
00192 
00193     if (m_errorString != "") {
00194         error = m_errorString;
00195     }
00196     m_errorString = "";
00197 
00198     getDataModelsSparse(models, reporter);
00199 
00200     if (m_errorString == "" && error != "") {
00201         m_errorString = error;
00202     }
00203 
00204     return models;
00205 }
00206 
00207 void
00208 RDFImporterImpl::getDataModelsAudio(std::vector<Model *> &models,
00209                                     ProgressReporter *reporter)
00210 {
00211     Nodes sigs = m_store->match
00212         (Triple(Node(), Uri("a"), expand("mo:Signal"))).subjects();
00213 
00214     foreach (Node sig, sigs) {
00215         
00216         Node file = m_store->complete(Triple(Node(), expand("mo:encodes"), sig));
00217         if (file == Node()) {
00218             file = m_store->complete(Triple(sig, expand("mo:available_as"), Node()));
00219         }
00220         if (file == Node()) {
00221             cerr << "RDFImporterImpl::getDataModelsAudio: ERROR: No source for signal " << sig << endl;
00222             continue;
00223         }
00224 
00225         QString signal = sig.value;
00226         QString source = file.value;
00227 
00228         SVDEBUG << "NOTE: Seeking signal source \"" << source
00229                 << "\"..." << endl;
00230 
00231         FileSource *fs = new FileSource(source, reporter);
00232         if (fs->isAvailable()) {
00233             SVDEBUG << "NOTE: Source is available: Local filename is \""
00234                     << fs->getLocalFilename()
00235                     << "\"..." << endl;
00236         }
00237             
00238 #ifdef NO_SV_GUI
00239         if (!fs->isAvailable()) {
00240             m_errorString = QString("Signal source \"%1\" is not available").arg(source);
00241             delete fs;
00242             continue;
00243         }
00244 #else
00245         if (!fs->isAvailable()) {
00246             SVDEBUG << "NOTE: Signal source \"" << source
00247                     << "\" is not available, using file finder..." << endl;
00248             FileFinder *ff = FileFinder::getInstance();
00249             if (ff) {
00250                 QString path = ff->find(FileFinder::AudioFile,
00251                                         fs->getLocation(),
00252                                         m_uristring);
00253                 if (path != "") {
00254                     cerr << "File finder returns: \"" << path
00255                               << "\"" << endl;
00256                     delete fs;
00257                     fs = new FileSource(path, reporter);
00258                     if (!fs->isAvailable()) {
00259                         delete fs;
00260                         m_errorString = QString("Signal source \"%1\" is not available").arg(source);
00261                         continue;
00262                     }
00263                 }
00264             }
00265         }
00266 #endif
00267 
00268         if (reporter) {
00269             reporter->setMessage(RDFImporter::tr("Importing audio referenced in RDF..."));
00270         }
00271         fs->waitForData();
00272         WaveFileModel *newModel = new WaveFileModel(*fs, m_sampleRate);
00273         if (newModel->isOK()) {
00274             cerr << "Successfully created wave file model from source at \"" << source << "\"" << endl;
00275             models.push_back(newModel);
00276             m_audioModelMap[signal] = newModel;
00277             if (m_sampleRate == 0) {
00278                 m_sampleRate = newModel->getSampleRate();
00279             }
00280         } else {
00281             m_errorString = QString("Failed to create wave file model from source at \"%1\"").arg(source);
00282             delete newModel;
00283         }
00284         delete fs;
00285     }
00286 }
00287 
00288 void
00289 RDFImporterImpl::getDataModelsDense(std::vector<Model *> &models,
00290                                     ProgressReporter *reporter)
00291 {
00292     if (reporter) {
00293         reporter->setMessage(RDFImporter::tr("Importing dense signal data from RDF..."));
00294     }
00295 
00296     Nodes sigFeatures = m_store->match
00297         (Triple(Node(), expand("af:signal_feature"), Node())).objects();
00298 
00299     foreach (Node sf, sigFeatures) {
00300 
00301         if (sf.type != Node::URI && sf.type != Node::Blank) continue;
00302         
00303         Node t = m_store->complete(Triple(sf, expand("a"), Node()));
00304         Node v = m_store->complete(Triple(sf, expand("af:value"), Node()));
00305 
00306         QString feature = sf.value;
00307         QString type = t.value;
00308         QString value = v.value;
00309         
00310         if (type == "" || value == "") continue;
00311 
00312         int sampleRate = 0;
00313         int windowLength = 0;
00314         int hopSize = 0;
00315         int width = 0;
00316         int height = 0;
00317         getDenseFeatureProperties
00318             (feature, sampleRate, windowLength, hopSize, width, height);
00319 
00320         if (sampleRate != 0 && sampleRate != m_sampleRate) {
00321             cerr << "WARNING: Sample rate in dense feature description does not match our underlying rate -- using rate from feature description" << endl;
00322         }
00323         if (sampleRate == 0) sampleRate = m_sampleRate;
00324 
00325         if (hopSize == 0) {
00326             cerr << "WARNING: Dense feature description does not specify a hop size -- assuming 1" << endl;
00327             hopSize = 1;
00328         }
00329 
00330         if (height == 0) {
00331             cerr << "WARNING: Dense feature description does not specify feature signal dimensions -- assuming one-dimensional (height = 1)" << endl;
00332             height = 1;
00333         }
00334 
00335         QStringList values = value.split(' ', QString::SkipEmptyParts);
00336 
00337         if (values.empty()) {
00338             cerr << "WARNING: Dense feature description does not specify any values!" << endl;
00339             continue;
00340         }
00341 
00342         if (height == 1) {
00343 
00344             SparseTimeValueModel *m = new SparseTimeValueModel
00345                 (sampleRate, hopSize, false);
00346 
00347             for (int j = 0; j < values.size(); ++j) {
00348                 float f = values[j].toFloat();
00349                 SparseTimeValueModel::Point point(j * hopSize, f, "");
00350                 m->addPoint(point);
00351             }
00352 
00353             getDenseModelTitle(m, feature, type);
00354         
00355             m->setRDFTypeURI(type);
00356 
00357             models.push_back(m);
00358 
00359         } else {
00360 
00361             EditableDenseThreeDimensionalModel *m =
00362                 new EditableDenseThreeDimensionalModel
00363                 (sampleRate, hopSize, height, 
00364                  EditableDenseThreeDimensionalModel::NoCompression, false);
00365             
00366             EditableDenseThreeDimensionalModel::Column column;
00367 
00368             int x = 0;
00369 
00370             for (int j = 0; j < values.size(); ++j) {
00371                 if (j % height == 0 && !column.empty()) {
00372                     m->setColumn(x++, column);
00373                     column.clear();
00374                 }
00375                 column.push_back(values[j].toFloat());
00376             }
00377 
00378             if (!column.empty()) {
00379                 m->setColumn(x++, column);
00380             }
00381 
00382             getDenseModelTitle(m, feature, type);
00383         
00384             m->setRDFTypeURI(type);
00385 
00386             models.push_back(m);
00387         }
00388     }
00389 }
00390 
00391 void
00392 RDFImporterImpl::getDenseModelTitle(Model *m,
00393                                     QString featureUri,
00394                                     QString featureTypeUri)
00395 {
00396     Node n = m_store->complete
00397         (Triple(Uri(featureUri), expand("dc:title"), Node()));
00398 
00399     if (n.type == Node::Literal && n.value != "") {
00400         SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal) \"" << n.value << "\"" << endl;
00401         m->setObjectName(n.value);
00402         return;
00403     }
00404 
00405     n = m_store->complete
00406         (Triple(Uri(featureTypeUri), expand("dc:title"), Node()));
00407 
00408     if (n.type == Node::Literal && n.value != "") {
00409         SVDEBUG << "RDFImporterImpl::getDenseModelTitle: Title (from signal type) \"" << n.value << "\"" << endl;
00410         m->setObjectName(n.value);
00411         return;
00412     }
00413 
00414     SVDEBUG << "RDFImporterImpl::getDenseModelTitle: No title available for feature <" << featureUri << ">" << endl;
00415 }
00416 
00417 void
00418 RDFImporterImpl::getDenseFeatureProperties(QString featureUri,
00419                                            int &sampleRate, int &windowLength,
00420                                            int &hopSize, int &width, int &height)
00421 {
00422     Node dim = m_store->complete
00423         (Triple(Uri(featureUri), expand("af:dimensions"), Node()));
00424 
00425     cerr << "Dimensions = \"" << dim.value << "\"" << endl;
00426 
00427     if (dim.type == Node::Literal && dim.value != "") {
00428         QStringList dl = dim.value.split(" ");
00429         if (dl.empty()) dl.push_back(dim.value);
00430         if (dl.size() > 0) height = dl[0].toInt();
00431         if (dl.size() > 1) width = dl[1].toInt();
00432     }
00433     
00434     // Looking for rate, hop, window from:
00435     //
00436     // ?feature mo:time ?time .
00437     // ?time a tl:Interval .
00438     // ?time tl:onTimeLine ?timeline .
00439     // ?map tl:rangeTimeLine ?timeline .
00440     // ?map tl:sampleRate ?rate .
00441     // ?map tl:hopSize ?hop .
00442     // ?map tl:windowLength ?window .
00443 
00444     Node interval = m_store->complete(Triple(Uri(featureUri), expand("mo:time"), Node()));
00445 
00446     if (!m_store->contains(Triple(interval, expand("a"), expand("tl:Interval")))) {
00447         cerr << "RDFImporterImpl::getDenseFeatureProperties: Feature time node "
00448              << interval << " is not a tl:Interval" << endl;
00449         return;
00450     }
00451 
00452     Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
00453     
00454     if (tl == Node()) {
00455         cerr << "RDFImporterImpl::getDenseFeatureProperties: Interval node "
00456              << interval << " lacks tl:onTimeLine property" << endl;
00457         return;
00458     }
00459 
00460     Node map = m_store->complete(Triple(Node(), expand("tl:rangeTimeLine"), tl));
00461     
00462     if (map == Node()) {
00463         cerr << "RDFImporterImpl::getDenseFeatureProperties: No map for "
00464              << "timeline node " << tl << endl;
00465     }
00466 
00467     PropertyObject po(m_store, "tl:", map);
00468 
00469     if (po.hasProperty("sampleRate")) {
00470         sampleRate = po.getProperty("sampleRate").toInt();
00471     }
00472     if (po.hasProperty("hopSize")) {
00473         hopSize = po.getProperty("hopSize").toInt();
00474     }
00475     if (po.hasProperty("windowLength")) {
00476         windowLength = po.getProperty("windowLength").toInt();
00477     }
00478 
00479     cerr << "sr = " << sampleRate << ", hop = " << hopSize << ", win = " << windowLength << endl;
00480 }
00481 
00482 void
00483 RDFImporterImpl::getDataModelsSparse(std::vector<Model *> &models,
00484                                      ProgressReporter *reporter)
00485 {
00486     if (reporter) {
00487         reporter->setMessage(RDFImporter::tr("Importing event data from RDF..."));
00488     }
00489 
00490     /*
00491       This function is only used for sparse data (for dense data we
00492       would be in getDataModelsDense instead).
00493 
00494       Our query is intended to retrieve every thing that has a time,
00495       and every feature type and value associated with a thing that
00496       has a time.
00497 
00498       We will then need to refine this big bag of results into a set
00499       of data models.
00500 
00501       Results that have different source signals should go into
00502       different models.
00503 
00504       Results that have different feature types should go into
00505       different models.
00506     */
00507 
00508     Nodes sigs = m_store->match
00509         (Triple(Node(), expand("a"), expand("mo:Signal"))).subjects();
00510 
00511     // Map from timeline uri to event type to dimensionality to
00512     // presence of duration to model ptr.  Whee!
00513     std::map<QString, std::map<QString, std::map<int, std::map<bool, Model *> > > >
00514         modelMap;
00515 
00516     foreach (Node sig, sigs) {
00517         
00518         Node interval = m_store->complete(Triple(sig, expand("mo:time"), Node()));
00519         if (interval == Node()) continue;
00520 
00521         Node tl = m_store->complete(Triple(interval, expand("tl:onTimeLine"), Node()));
00522         if (tl == Node()) continue;
00523 
00524         Nodes times = m_store->match(Triple(Node(), expand("tl:onTimeLine"), tl)).subjects();
00525         
00526         foreach (Node tn, times) {
00527             
00528             Nodes timedThings = m_store->match(Triple(Node(), expand("event:time"), tn)).subjects();
00529 
00530             foreach (Node thing, timedThings) {
00531                 
00532                 Node typ = m_store->complete(Triple(thing, expand("a"), Node()));
00533                 if (typ == Node()) continue;
00534 
00535                 Node valu = m_store->complete(Triple(thing, expand("af:feature"), Node()));
00536 
00537                 QString source = sig.value;
00538                 QString timeline = tl.value;
00539                 QString type = typ.value;
00540                 QString thinguri = thing.value;
00541 
00542                 /*
00543                   For sparse data, the determining factors in deciding
00544                   what model to use are: Do the features have values?
00545                   and Do the features have duration?
00546 
00547                   We can run through the results and check off whether
00548                   we find values and duration for each of the
00549                   source+type keys, and then run through the
00550                   source+type keys pushing each of the results into a
00551                   suitable model.
00552 
00553                   Unfortunately, at this point we do not yet have any
00554                   actual timing data (time/duration) -- just the time
00555                   URI.
00556 
00557                   What we _could_ do is to create one of each type of
00558                   model at the start, for each of the source+type
00559                   keys, and then push each feature into the relevant
00560                   model depending on what we find out about it.  Then
00561                   return only non-empty models.
00562                 */
00563 
00564                 QString label = "";
00565                 bool text = (type.contains("Text") || type.contains("text")); // Ha, ha
00566                 bool note = (type.contains("Note") || type.contains("note")); // Guffaw
00567 
00568                 if (text) {
00569                     label = m_store->complete(Triple(thing, expand("af:text"), Node())).value;
00570                 }
00571                 
00572                 if (label == "") {
00573                     label = m_store->complete(Triple(thing, expand("rdfs:label"), Node())).value;
00574                 }
00575 
00576                 RealTime time;
00577                 RealTime duration;
00578 
00579 //                bool haveTime = false;
00580                 bool haveDuration = false;
00581 
00582                 Node at = m_store->complete(Triple(tn, expand("tl:at"), Node()));
00583 
00584                 if (at != Node()) {
00585                     time = RealTime::fromXsdDuration(at.value.toStdString());
00586 //                    haveTime = true;
00587                 } else {
00589     // beginsAt -> start
00590     // onTimeLine -> timeline
00591 
00592                     Node start = m_store->complete(Triple(tn, expand("tl:beginsAt"), Node()));
00593                     Node dur = m_store->complete(Triple(tn, expand("tl:duration"), Node()));
00594                     if (start != Node() && dur != Node()) {
00595                         time = RealTime::fromXsdDuration
00596                             (start.value.toStdString());
00597                         duration = RealTime::fromXsdDuration
00598                             (dur.value.toStdString());
00599 //                        haveTime = haveDuration = true;
00600                     }
00601                 }
00602 
00603                 QString valuestring = valu.value;
00604                 std::vector<float> values;
00605 
00606                 if (valuestring != "") {
00607                     QStringList vsl = valuestring.split(" ", QString::SkipEmptyParts);
00608                     for (int j = 0; j < vsl.size(); ++j) {
00609                         bool success = false;
00610                         float v = vsl[j].toFloat(&success);
00611                         if (success) values.push_back(v);
00612                     }
00613                 }
00614                 
00615                 int dimensions = 1;
00616                 if (values.size() == 1) dimensions = 2;
00617                 else if (values.size() > 1) dimensions = 3;
00618 
00619                 Model *model = 0;
00620 
00621                 if (modelMap[timeline][type][dimensions].find(haveDuration) ==
00622                     modelMap[timeline][type][dimensions].end()) {
00623 
00624 /*
00625             SVDEBUG << "Creating new model: source = " << source                      << ", type = " << type << ", dimensions = "
00626                       << dimensions << ", haveDuration = " << haveDuration
00627                       << ", time = " << time << ", duration = " << duration
00628                       << endl;
00629 */
00630             
00631                     if (!haveDuration) {
00632 
00633                         if (dimensions == 1) {
00634                             if (text) {
00635                                 model = new TextModel(m_sampleRate, 1, false);
00636                             } else {
00637                                 model = new SparseOneDimensionalModel(m_sampleRate, 1, false);
00638                             }
00639                         } else if (dimensions == 2) {
00640                             if (text) {
00641                                 model = new TextModel(m_sampleRate, 1, false);
00642                             } else {
00643                                 model = new SparseTimeValueModel(m_sampleRate, 1, false);
00644                             }
00645                         } else {
00646                             // We don't have a three-dimensional sparse model,
00647                             // so use a note model.  We do have some logic (in
00648                             // extractStructure below) for guessing whether
00649                             // this should after all have been a dense model,
00650                             // but it's hard to apply it because we don't have
00651                             // all the necessary timing data yet... hmm
00652                             model = new NoteModel(m_sampleRate, 1, false);
00653                         }
00654 
00655                     } else { // haveDuration
00656 
00657                         if (note || (dimensions > 2)) {
00658                             model = new NoteModel(m_sampleRate, 1, false);
00659                         } else {
00660                             // If our units are frequency or midi pitch, we
00661                             // should be using a note model... hm
00662                             model = new RegionModel(m_sampleRate, 1, false);
00663                         }
00664                     }
00665 
00666                     model->setRDFTypeURI(type);
00667 
00668                     if (m_audioModelMap.find(source) != m_audioModelMap.end()) {
00669                         cerr << "source model for " << model << " is " << m_audioModelMap[source] << endl;
00670                         model->setSourceModel(m_audioModelMap[source]);
00671                     }
00672 
00673                     QString title = m_store->complete
00674                         (Triple(typ, expand("dc:title"), Node())).value;
00675                     if (title == "") {
00676                         // take it from the end of the event type
00677                         title = type;
00678                         title.replace(QRegExp("^.*[/#]"), "");
00679                     }
00680                     model->setObjectName(title);
00681 
00682                     modelMap[timeline][type][dimensions][haveDuration] = model;
00683                     models.push_back(model);
00684                 }
00685 
00686                 model = modelMap[timeline][type][dimensions][haveDuration];
00687 
00688                 if (model) {
00689                     long ftime = RealTime::realTime2Frame(time, m_sampleRate);
00690                     long fduration = RealTime::realTime2Frame(duration, m_sampleRate);
00691                     fillModel(model, ftime, fduration, haveDuration, values, label);
00692                 }
00693             }
00694         }
00695     }
00696 }
00697 
00698 void
00699 RDFImporterImpl::fillModel(Model *model,
00700                            long ftime,
00701                            long fduration,
00702                            bool haveDuration,
00703                            std::vector<float> &values,
00704                            QString label)
00705 {
00706 //    SVDEBUG << "RDFImporterImpl::fillModel: adding point at frame " << ftime << endl;
00707 
00708     SparseOneDimensionalModel *sodm =
00709         dynamic_cast<SparseOneDimensionalModel *>(model);
00710     if (sodm) {
00711         SparseOneDimensionalModel::Point point(ftime, label);
00712         sodm->addPoint(point);
00713         return;
00714     }
00715 
00716     TextModel *tm =
00717         dynamic_cast<TextModel *>(model);
00718     if (tm) {
00719         TextModel::Point point
00720             (ftime,
00721              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
00722              label);
00723         tm->addPoint(point);
00724         return;
00725     }
00726 
00727     SparseTimeValueModel *stvm =
00728         dynamic_cast<SparseTimeValueModel *>(model);
00729     if (stvm) {
00730         SparseTimeValueModel::Point point
00731             (ftime, values.empty() ? 0.f : values[0], label);
00732         stvm->addPoint(point);
00733         return;
00734     }
00735 
00736     NoteModel *nm =
00737         dynamic_cast<NoteModel *>(model);
00738     if (nm) {
00739         if (haveDuration) {
00740             float value = 0.f, level = 1.f;
00741             if (!values.empty()) {
00742                 value = values[0];
00743                 if (values.size() > 1) {
00744                     level = values[1];
00745                 }
00746             }
00747             NoteModel::Point point(ftime, value, fduration, level, label);
00748             nm->addPoint(point);
00749         } else {
00750             float value = 0.f, duration = 1.f, level = 1.f;
00751             if (!values.empty()) {
00752                 value = values[0];
00753                 if (values.size() > 1) {
00754                     duration = values[1];
00755                     if (values.size() > 2) {
00756                         level = values[2];
00757                     }
00758                 }
00759             }
00760             NoteModel::Point point(ftime, value, duration, level, label);
00761             nm->addPoint(point);
00762         }
00763         return;
00764     }
00765 
00766     RegionModel *rm = 
00767         dynamic_cast<RegionModel *>(model);
00768     if (rm) {
00769         float value = 0.f;
00770         if (values.empty()) {
00771             // no values? map each unique label to a distinct value
00772             if (m_labelValueMap[model].find(label) == m_labelValueMap[model].end()) {
00773                 m_labelValueMap[model][label] = rm->getValueMaximum() + 1.f;
00774             }
00775             value = m_labelValueMap[model][label];
00776         } else {
00777             value = values[0];
00778         }
00779         if (haveDuration) {
00780             RegionModel::Point point(ftime, value, fduration, label);
00781             rm->addPoint(point);
00782         } else {
00783             // This won't actually happen -- we only create region models
00784             // if we do have duration -- but just for completeness
00785             float duration = 1.f;
00786             if (!values.empty()) {
00787                 value = values[0];
00788                 if (values.size() > 1) {
00789                     duration = values[1];
00790                 }
00791             }
00792             RegionModel::Point point(ftime, value, duration, label);
00793             rm->addPoint(point);
00794         }
00795         return;
00796     }
00797             
00798     cerr << "WARNING: RDFImporterImpl::fillModel: Unknown or unexpected model type" << endl;
00799     return;
00800 }
00801 
00802 RDFImporter::RDFDocumentType
00803 RDFImporter::identifyDocumentType(QString url)
00804 {
00805     bool haveAudio = false;
00806     bool haveAnnotations = false;
00807     bool haveRDF = false;
00808 
00809     BasicStore *store = 0;
00810 
00811     // This is not expected to return anything useful, but if it does
00812     // anything at all then we know we have RDF
00813     try {
00815         store = BasicStore::load(QUrl(url));
00816         Triple t = store->matchOnce(Triple());
00817         if (t != Triple()) haveRDF = true;
00818     } catch (std::exception &e) {
00819         // nothing; haveRDF will be false so the next bit catches it
00820     }
00821 
00822     if (!haveRDF) {
00823         delete store;
00824         return NotRDF;
00825     }
00826 
00827     store->addPrefix("mo", Uri("http://purl.org/ontology/mo/"));
00828     store->addPrefix("event", Uri("http://purl.org/NET/c4dm/event.owl#"));
00829     store->addPrefix("af", Uri("http://purl.org/ontology/af/"));
00830 
00831     // "MO-conformant" structure for audio files
00832 
00833     Node n = store->complete(Triple(Node(), Uri("a"), store->expand("mo:AudioFile")));
00834     if (n != Node() && n.type == Node::URI) {
00835 
00836         haveAudio = true;
00837 
00838     } else {
00839 
00840         // Sonic Annotator v0.2 and below used to write this structure
00841         // (which is not properly in conformance with the Music
00842         // Ontology)
00843 
00844         Nodes sigs = store->match(Triple(Node(), Uri("a"), store->expand("mo:Signal"))).subjects();
00845         foreach (Node sig, sigs) {
00846             Node aa = store->complete(Triple(sig, store->expand("mo:available_as"), Node()));
00847             if (aa != Node()) {
00848                 haveAudio = true;
00849                 break;
00850             }
00851         }
00852     }
00853 
00854     SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAudio = "
00855               << haveAudio << endl;
00856 
00857     // can't call complete() with two Nothing nodes
00858     n = store->matchOnce(Triple(Node(), store->expand("event:time"), Node())).c;
00859     if (n != Node()) {
00860         haveAnnotations = true;
00861     }
00862 
00863     if (!haveAnnotations) {
00864         // can't call complete() with two Nothing nodes
00865         n = store->matchOnce(Triple(Node(), store->expand("af:signal_feature"), Node())).c;
00866         if (n != Node()) {
00867             haveAnnotations = true;
00868         }
00869     }
00870 
00871     SVDEBUG << "NOTE: RDFImporter::identifyDocumentType: haveAnnotations = "
00872               << haveAnnotations << endl;
00873 
00874     delete store;
00875 
00876     if (haveAudio) {
00877         if (haveAnnotations) {
00878             return AudioRefAndAnnotations;
00879         } else {
00880             return AudioRef;
00881         }
00882     } else {
00883         if (haveAnnotations) {
00884             return Annotations;
00885         } else {
00886             return OtherRDFDocument;
00887         }
00888     }
00889 
00890     return OtherRDFDocument;
00891 }
00892