svcore
1.9
|
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 "RDFTransformFactory.h" 00017 00018 #include <map> 00019 #include <vector> 00020 00021 #include <QTextStream> 00022 #include <QUrl> 00023 00024 #include <iostream> 00025 #include <cmath> 00026 00027 #include "PluginRDFIndexer.h" 00028 #include "PluginRDFDescription.h" 00029 #include "base/ProgressReporter.h" 00030 #include "plugin/PluginIdentifier.h" 00031 00032 #include "transform/TransformFactory.h" 00033 00034 #include <dataquay/BasicStore.h> 00035 #include <dataquay/PropertyObject.h> 00036 00037 using Dataquay::Uri; 00038 using Dataquay::Node; 00039 using Dataquay::Nodes; 00040 using Dataquay::Triple; 00041 using Dataquay::Triples; 00042 using Dataquay::BasicStore; 00043 using Dataquay::PropertyObject; 00044 00045 00046 class RDFTransformFactoryImpl 00047 { 00048 public: 00049 RDFTransformFactoryImpl(QString url); 00050 virtual ~RDFTransformFactoryImpl(); 00051 00052 bool isRDF(); 00053 bool isOK(); 00054 QString getErrorString() const; 00055 00056 std::vector<Transform> getTransforms(ProgressReporter *); 00057 00058 static QString writeTransformToRDF(const Transform &, QString); 00059 00060 protected: 00061 BasicStore *m_store; 00062 QString m_urlString; 00063 QString m_errorString; 00064 bool m_isRDF; 00065 bool setOutput(Transform &, QString); 00066 bool setParameters(Transform &, QString); 00067 }; 00068 00069 00070 QString 00071 RDFTransformFactory::getKnownExtensions() 00072 { 00073 return "*.rdf *.n3 *.ttl"; 00074 } 00075 00076 RDFTransformFactory::RDFTransformFactory(QString url) : 00077 m_d(new RDFTransformFactoryImpl(url)) 00078 { 00079 } 00080 00081 RDFTransformFactory::~RDFTransformFactory() 00082 { 00083 delete m_d; 00084 } 00085 00086 bool 00087 RDFTransformFactory::isRDF() 00088 { 00089 return m_d->isRDF(); 00090 } 00091 00092 bool 00093 RDFTransformFactory::isOK() 00094 { 00095 return m_d->isOK(); 00096 } 00097 00098 QString 00099 RDFTransformFactory::getErrorString() const 00100 { 00101 return m_d->getErrorString(); 00102 } 00103 00104 std::vector<Transform> 00105 RDFTransformFactory::getTransforms(ProgressReporter *r) 00106 { 00107 return m_d->getTransforms(r); 00108 } 00109 00110 QString 00111 RDFTransformFactory::writeTransformToRDF(const Transform &t, QString f) 00112 { 00113 return RDFTransformFactoryImpl::writeTransformToRDF(t, f); 00114 } 00115 00116 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) : 00117 m_store(new BasicStore), 00118 m_urlString(url), 00119 m_isRDF(false) 00120 { 00122 m_store->addPrefix("vamp", Uri("http://purl.org/ontology/vamp/")); 00123 try { 00124 QUrl qurl; 00125 if (url.startsWith("file:")) { 00126 qurl = QUrl(url); 00127 } else { 00128 qurl = QUrl::fromLocalFile(url); 00129 } 00130 m_store->import(qurl, BasicStore::ImportIgnoreDuplicates); 00131 m_isRDF = true; 00132 } catch (...) { } 00133 } 00134 00135 RDFTransformFactoryImpl::~RDFTransformFactoryImpl() 00136 { 00137 delete m_store; 00138 } 00139 00140 bool 00141 RDFTransformFactoryImpl::isRDF() 00142 { 00143 return m_isRDF; 00144 } 00145 00146 bool 00147 RDFTransformFactoryImpl::isOK() 00148 { 00149 return (m_errorString == ""); 00150 } 00151 00152 QString 00153 RDFTransformFactoryImpl::getErrorString() const 00154 { 00155 return m_errorString; 00156 } 00157 00158 std::vector<Transform> 00159 RDFTransformFactoryImpl::getTransforms(ProgressReporter *) 00160 { 00161 std::vector<Transform> transforms; 00162 00163 std::map<QString, Transform> uriTransformMap; 00164 00165 Nodes tnodes = m_store->match 00166 (Triple(Node(), Uri("a"), m_store->expand("vamp:Transform"))).subjects(); 00167 00168 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); 00169 00170 foreach (Node tnode, tnodes) { 00171 00172 Node pnode = m_store->complete 00173 (Triple(tnode, m_store->expand("vamp:plugin"), Node())); 00174 00175 if (pnode == Node()) { 00176 cerr << "RDFTransformFactory: WARNING: No vamp:plugin for " 00177 << "vamp:Transform node " << tnode 00178 << ", skipping this transform" << endl; 00179 continue; 00180 } 00181 00182 QString transformUri = tnode.value; 00183 QString pluginUri = pnode.value; 00184 00185 QString pluginId = indexer->getIdForPluginURI(pluginUri); 00186 if (pluginId == "") { 00187 cerr << "RDFTransformFactory: WARNING: Unknown plugin <" 00188 << pluginUri << "> for transform <" 00189 << transformUri << ">, skipping this transform" 00190 << endl; 00191 continue; 00192 } 00193 00194 Transform transform; 00195 transform.setPluginIdentifier(pluginId); 00196 00197 if (!setOutput(transform, transformUri)) { 00198 return transforms; 00199 } 00200 00201 if (!setParameters(transform, transformUri)) { 00202 return transforms; 00203 } 00204 00205 uriTransformMap[transformUri] = transform; 00206 00207 static const char *optionals[] = { 00208 "program", 00209 "summary_type", 00210 "step_size", 00211 "block_size", 00212 "window_type", 00213 "sample_rate", 00214 "start", 00215 "duration" 00216 }; 00217 00218 for (int j = 0; j < int(sizeof(optionals)/sizeof(optionals[0])); ++j) { 00219 00220 QString optional = optionals[j]; 00221 00222 Node onode = m_store->complete 00223 (Triple(Uri(transformUri), 00224 m_store->expand(QString("vamp:") + optional), Node())); 00225 00226 if (onode.type != Node::Literal) continue; 00227 00228 if (optional == "program") { 00229 transform.setProgram(onode.value); 00230 } else if (optional == "summary_type") { 00231 transform.setSummaryType 00232 (transform.stringToSummaryType(onode.value)); 00233 } else if (optional == "step_size") { 00234 transform.setStepSize(onode.value.toUInt()); 00235 } else if (optional == "block_size") { 00236 transform.setBlockSize(onode.value.toUInt()); 00237 } else if (optional == "window_type") { 00238 transform.setWindowType 00239 (Window<float>::getTypeForName 00240 (onode.value.toLower().toStdString())); 00241 } else if (optional == "sample_rate") { 00242 transform.setSampleRate(onode.value.toFloat()); 00243 } else if (optional == "start") { 00244 transform.setStartTime 00245 (RealTime::fromXsdDuration(onode.value.toStdString())); 00246 } else if (optional == "duration") { 00247 transform.setDuration 00248 (RealTime::fromXsdDuration(onode.value.toStdString())); 00249 } else { 00250 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional << "\"" << endl; 00251 } 00252 } 00253 00254 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl; 00255 cerr << transform.toXmlString() << endl; 00256 00257 transforms.push_back(transform); 00258 } 00259 00260 return transforms; 00261 } 00262 00263 bool 00264 RDFTransformFactoryImpl::setOutput(Transform &transform, 00265 QString transformUri) 00266 { 00267 Node outputNode = m_store->complete 00268 (Triple(Uri(transformUri), m_store->expand("vamp:output"), Node())); 00269 00270 if (outputNode == Node()) return true; 00271 00272 if (outputNode.type != Node::URI && outputNode.type != Node::Blank) { 00273 m_errorString = QString("vamp:output for output of transform <%1> is not a URI or blank node").arg(transformUri); 00274 return false; 00275 } 00276 00277 // Now, outputNode might be the subject of a triple within m_store 00278 // that tells us the vamp:identifier, or it might be the subject 00279 // of a triple within the indexer that tells us it 00280 00281 Node identNode = m_store->complete 00282 (Triple(outputNode, m_store->expand("vamp:identifier"), Node())); 00283 00284 if (identNode == Node()) { 00285 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); 00286 const BasicStore *index = indexer->getIndex(); 00287 identNode = index->complete 00288 (Triple(outputNode, index->expand("vamp:identifier"), Node())); 00289 } 00290 00291 if (identNode == Node() || identNode.type != Node::Literal) { 00292 m_errorString = QString("No vamp:identifier found for output of transform <%1>, or vamp:identifier is not a literal").arg(transformUri); 00293 return false; 00294 } 00295 00296 transform.setOutput(identNode.value); 00297 00298 return true; 00299 } 00300 00301 00302 bool 00303 RDFTransformFactoryImpl::setParameters(Transform &transform, 00304 QString transformUri) 00305 { 00306 Nodes bindings = m_store->match 00307 (Triple(Uri(transformUri), m_store->expand("vamp:parameter_binding"), Node())).objects(); 00308 00309 foreach (Node binding, bindings) { 00310 00311 Node paramNode = m_store->complete 00312 (Triple(binding, m_store->expand("vamp:parameter"), Node())); 00313 00314 if (paramNode == Node()) { 00315 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:parameter for binding " << binding << endl; 00316 continue; 00317 } 00318 00319 Node valueNode = m_store->complete 00320 (Triple(binding, m_store->expand("vamp:value"), Node())); 00321 00322 if (paramNode == Node()) { 00323 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:value for binding " << binding << endl; 00324 continue; 00325 } 00326 00327 // As with output above, paramNode might be the subject of a 00328 // triple within m_store that tells us the vamp:identifier, or 00329 // it might be the subject of a triple within the indexer that 00330 // tells us it 00331 00332 Node idNode = m_store->complete 00333 (Triple(paramNode, m_store->expand("vamp:identifier"), Node())); 00334 00335 if (idNode == Node()) { 00336 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance(); 00337 const BasicStore *index = indexer->getIndex(); 00338 idNode = index->complete 00339 (Triple(paramNode, index->expand("vamp:identifier"), Node())); 00340 } 00341 00342 if (idNode == Node() || idNode.type != Node::Literal) { 00343 cerr << "RDFTransformFactoryImpl::setParameters: No vamp:identifier for parameter " << paramNode << endl; 00344 continue; 00345 } 00346 00347 transform.setParameter(idNode.value, valueNode.value.toFloat()); 00348 } 00349 00350 return true; 00351 } 00352 00353 QString 00354 RDFTransformFactoryImpl::writeTransformToRDF(const Transform &transform, 00355 QString uri) 00356 { 00357 QString str; 00358 QTextStream s(&str); 00359 00360 // assumes the usual prefixes are available; requires that uri be 00361 // a local fragment (e.g. ":transform") rather than a uri enclosed 00362 // in <>, so that we can suffix it if need be 00363 00364 QString pluginId = transform.getPluginIdentifier(); 00365 QString pluginUri = PluginRDFIndexer::getInstance()->getURIForPluginId(pluginId); 00366 00367 if (pluginUri != "") { 00368 s << uri << " a vamp:Transform ;" << endl; 00369 s << " vamp:plugin <" << QUrl(pluginUri).toEncoded().data() << "> ;" << endl; 00370 } else { 00371 cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No plugin URI available for plugin id \"" << pluginId << "\", writing synthetic plugin and library resources" << endl; 00372 QString type, soname, label; 00373 PluginIdentifier::parseIdentifier(pluginId, type, soname, label); 00374 s << uri << "_plugin a vamp:Plugin ;" << endl; 00375 s << " vamp:identifier \"" << label << "\" .\n" << endl; 00376 s << uri << "_library a vamp:PluginLibrary ;" << endl; 00377 s << " vamp:identifier \"" << soname << "\" ;" << endl; 00378 s << " vamp:available_plugin " << uri << "_plugin .\n" << endl; 00379 s << uri << " a vamp:Transform ;" << endl; 00380 s << " vamp:plugin " << uri << "_plugin ;" << endl; 00381 } 00382 00383 PluginRDFDescription description(pluginId); 00384 QString outputId = transform.getOutput(); 00385 QString outputUri = description.getOutputUri(outputId); 00386 00387 if (transform.getOutput() != "" && outputUri == "") { 00388 cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No output URI available for transform output id \"" << transform.getOutput() << "\", writing a synthetic output resource" << endl; 00389 } 00390 00391 if (transform.getStepSize() != 0) { 00392 s << " vamp:step_size \"" << transform.getStepSize() << "\"^^xsd:int ; " << endl; 00393 } 00394 if (transform.getBlockSize() != 0) { 00395 s << " vamp:block_size \"" << transform.getBlockSize() << "\"^^xsd:int ; " << endl; 00396 } 00397 if (transform.getStartTime() != RealTime::zeroTime) { 00398 s << " vamp:start \"" << transform.getStartTime().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl; 00399 } 00400 if (transform.getDuration() != RealTime::zeroTime) { 00401 s << " vamp:duration \"" << transform.getDuration().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl; 00402 } 00403 if (transform.getSampleRate() != 0) { 00404 s << " vamp:sample_rate \"" << transform.getSampleRate() << "\"^^xsd:float ; " << endl; 00405 } 00406 00407 QString program = transform.getProgram(); 00408 if (program != "") { 00409 s << " vamp:program \"\"\"" << program << "\"\"\" ;" << endl; 00410 } 00411 00412 QString summary = transform.summaryTypeToString(transform.getSummaryType()); 00413 if (summary != "") { 00414 s << " vamp:summary_type \"" << summary << "\" ;" << endl; 00415 } 00416 00417 Transform::ParameterMap parameters = transform.getParameters(); 00418 for (Transform::ParameterMap::const_iterator i = parameters.begin(); 00419 i != parameters.end(); ++i) { 00420 QString name = i->first; 00421 float value = i->second; 00422 s << " vamp:parameter_binding [" << endl; 00423 s << " vamp:parameter [ vamp:identifier \"" << name << "\" ] ;" << endl; 00424 s << " vamp:value \"" << value << "\"^^xsd:float ;" << endl; 00425 s << " ] ;" << endl; 00426 } 00427 00428 if (outputUri != "") { 00429 s << " vamp:output <" << QUrl(outputUri).toEncoded().data() << "> ." << endl; 00430 } else if (outputId != "") { 00431 s << " vamp:output [ vamp:identifier \"" << outputId << "\" ] ." << endl; 00432 } else { 00433 s << " ." << endl; 00434 } 00435 00436 return str; 00437 } 00438