RDFTransformFactory.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 "RDFTransformFactory.h"
17 
18 #include <map>
19 #include <vector>
20 
21 #include <QTextStream>
22 #include <QUrl>
23 
24 #include <iostream>
25 #include <cmath>
26 
27 #include "PluginRDFIndexer.h"
28 #include "PluginRDFDescription.h"
29 #include "base/ProgressReporter.h"
31 
33 
34 #include <dataquay/BasicStore.h>
35 #include <dataquay/PropertyObject.h>
36 
37 using Dataquay::Uri;
38 using Dataquay::Node;
39 using Dataquay::Nodes;
40 using Dataquay::Triple;
41 using Dataquay::Triples;
42 using Dataquay::BasicStore;
43 using Dataquay::PropertyObject;
44 
45 
47 {
48 public:
49  RDFTransformFactoryImpl(QString url);
50  virtual ~RDFTransformFactoryImpl();
51 
52  bool isRDF();
53  bool isOK();
54  QString getErrorString() const;
55 
56  std::vector<Transform> getTransforms(ProgressReporter *);
57 
58  static QString writeTransformToRDF(const Transform &, QString);
59 
60 protected:
61  BasicStore *m_store;
62  QString m_urlString;
63  QString m_errorString;
64  bool m_isRDF;
65  bool setOutput(Transform &, QString);
66  bool setParameters(Transform &, QString);
67 };
68 
69 
70 QString
72 {
73  return "*.rdf *.n3 *.ttl";
74 }
75 
77  m_d(new RDFTransformFactoryImpl(url))
78 {
79 }
80 
82 {
83  delete m_d;
84 }
85 
86 bool
88 {
89  return m_d->isRDF();
90 }
91 
92 bool
94 {
95  return m_d->isOK();
96 }
97 
98 QString
100 {
101  return m_d->getErrorString();
102 }
103 
104 std::vector<Transform>
106 {
107  return m_d->getTransforms(r);
108 }
109 
110 QString
112 {
114 }
115 
117  m_store(new BasicStore),
118  m_urlString(url),
119  m_isRDF(false)
120 {
122  m_store->addPrefix("vamp", Uri("http://purl.org/ontology/vamp/"));
123  try {
124  QUrl qurl;
125  if (url.startsWith("file:")) {
126  qurl = QUrl(url);
127  } else {
128  qurl = QUrl::fromLocalFile(url);
129  }
130  m_store->import(qurl, BasicStore::ImportIgnoreDuplicates);
131  m_isRDF = true;
132  } catch (const std::exception &e) {
133  // The file is not RDF -- we report this by returning false
134  // from isRDF (because we have not reached the m_isRDF = true
135  // line above), but we also set the error string
136  m_errorString = e.what();
137  }
138 }
139 
141 {
142  delete m_store;
143 }
144 
145 bool
147 {
148  return m_isRDF;
149 }
150 
151 bool
153 {
154  return m_isRDF && (m_errorString == "");
155 }
156 
157 QString
159 {
160  return m_errorString;
161 }
162 
163 std::vector<Transform>
165 {
166  std::vector<Transform> transforms;
167 
168  if (!m_isRDF) return transforms;
169 
170  std::map<QString, Transform> uriTransformMap;
171 
172  Nodes tnodes = m_store->match
173  (Triple(Node(), Uri("a"), m_store->expand("vamp:Transform"))).subjects();
174 
176 
177  foreach (Node tnode, tnodes) {
178 
179  Node pnode = m_store->complete
180  (Triple(tnode, m_store->expand("vamp:plugin"), Node()));
181 
182  if (pnode == Node()) {
183  cerr << "RDFTransformFactory: WARNING: No vamp:plugin for "
184  << "vamp:Transform node " << tnode
185  << ", skipping this transform" << endl;
186  continue;
187  }
188 
189  QString transformUri = tnode.value;
190  QString pluginUri = pnode.value;
191 
192  QString pluginId = indexer->getIdForPluginURI(pluginUri);
193  if (pluginId == "") {
194  cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
195  << pluginUri << "> for transform <"
196  << transformUri << ">, skipping this transform"
197  << endl;
198  continue;
199  }
200 
201  Transform transform;
202  transform.setPluginIdentifier(pluginId);
203 
204  if (!setOutput(transform, transformUri)) {
205  return transforms;
206  }
207 
208  if (!setParameters(transform, transformUri)) {
209  return transforms;
210  }
211 
212  uriTransformMap[transformUri] = transform;
213 
214  static const char *optionals[] = {
215  "program",
216  "summary_type",
217  "step_size",
218  "block_size",
219  "window_type",
220  "sample_rate",
221  "start",
222  "duration",
223  "plugin_version"
224  };
225 
226  for (int j = 0; j < int(sizeof(optionals)/sizeof(optionals[0])); ++j) {
227 
228  QString optional = optionals[j];
229 
230  Node onode = m_store->complete
231  (Triple(Uri(transformUri),
232  m_store->expand(QString("vamp:") + optional), Node()));
233 
234  if (onode.type != Node::Literal) continue;
235 
236  if (optional == "program") {
237  transform.setProgram(onode.value);
238  } else if (optional == "summary_type") {
239  transform.setSummaryType
240  (transform.stringToSummaryType(onode.value));
241  } else if (optional == "step_size") {
242  transform.setStepSize(onode.value.toUInt());
243  } else if (optional == "block_size") {
244  transform.setBlockSize(onode.value.toUInt());
245  } else if (optional == "window_type") {
246  transform.setWindowType
248  (onode.value.toLower().toStdString()));
249  } else if (optional == "sample_rate") {
250  transform.setSampleRate(onode.value.toFloat());
251  } else if (optional == "start") {
252  RealTime start = RealTime::fromXsdDuration(onode.value.toStdString());
253  transform.setStartTime(start);
254  } else if (optional == "duration") {
255  RealTime duration = RealTime::fromXsdDuration(onode.value.toStdString());
256  transform.setDuration(duration);
257  if (duration == RealTime::zeroTime) {
258  cerr << "\nRDFTransformFactory: WARNING: Duration is specified as \"" << onode.value << "\" in RDF file,\n but this evaluates to zero when parsed as an xsd:duration datatype.\n The duration property will therefore be ignored.\n To specify start time and duration use the xsd:duration format,\n for example \"PT2.5S\"^^xsd:duration (for 2.5 seconds).\n\n";
259  }
260  } else if (optional == "plugin_version") {
261  transform.setPluginVersion(onode.value);
262  } else {
263  cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional << "\"" << endl;
264  }
265  }
266 
267  cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
268  cerr << transform.toXmlString() << endl;
269 
270  transforms.push_back(transform);
271  }
272 
273  return transforms;
274 }
275 
276 bool
278  QString transformUri)
279 {
280  Node outputNode = m_store->complete
281  (Triple(Uri(transformUri), m_store->expand("vamp:output"), Node()));
282 
283  if (outputNode == Node()) return true;
284 
285  if (outputNode.type != Node::URI && outputNode.type != Node::Blank) {
286  m_errorString = QString("vamp:output for output of transform <%1> is not a URI or blank node").arg(transformUri);
287  return false;
288  }
289 
290  // Now, outputNode might be the subject of a triple within m_store
291  // that tells us the vamp:identifier, or it might be the subject
292  // of a triple within the indexer that tells us it
293 
294  Node identNode = m_store->complete
295  (Triple(outputNode, m_store->expand("vamp:identifier"), Node()));
296 
297  if (identNode == Node()) {
299  const BasicStore *index = indexer->getIndex();
300  identNode = index->complete
301  (Triple(outputNode, index->expand("vamp:identifier"), Node()));
302  }
303 
304  if (identNode == Node() || identNode.type != Node::Literal) {
305  m_errorString = QString("No vamp:identifier found for output of transform <%1>, or vamp:identifier is not a literal").arg(transformUri);
306  return false;
307  }
308 
309  transform.setOutput(identNode.value);
310 
311  return true;
312 }
313 
314 
315 bool
317  QString transformUri)
318 {
319  Nodes bindings = m_store->match
320  (Triple(Uri(transformUri), m_store->expand("vamp:parameter_binding"), Node())).objects();
321 
322  foreach (Node binding, bindings) {
323 
324  Node paramNode = m_store->complete
325  (Triple(binding, m_store->expand("vamp:parameter"), Node()));
326 
327  if (paramNode == Node()) {
328  cerr << "RDFTransformFactoryImpl::setParameters: No vamp:parameter for binding " << binding << endl;
329  continue;
330  }
331 
332  Node valueNode = m_store->complete
333  (Triple(binding, m_store->expand("vamp:value"), Node()));
334 
335  if (paramNode == Node()) {
336  cerr << "RDFTransformFactoryImpl::setParameters: No vamp:value for binding " << binding << endl;
337  continue;
338  }
339 
340  // As with output above, paramNode might be the subject of a
341  // triple within m_store that tells us the vamp:identifier, or
342  // it might be the subject of a triple within the indexer that
343  // tells us it
344 
345  Node idNode = m_store->complete
346  (Triple(paramNode, m_store->expand("vamp:identifier"), Node()));
347 
348  if (idNode == Node()) {
350  const BasicStore *index = indexer->getIndex();
351  idNode = index->complete
352  (Triple(paramNode, index->expand("vamp:identifier"), Node()));
353  }
354 
355  if (idNode == Node() || idNode.type != Node::Literal) {
356  cerr << "RDFTransformFactoryImpl::setParameters: No vamp:identifier for parameter " << paramNode << endl;
357  continue;
358  }
359 
360  transform.setParameter(idNode.value, valueNode.value.toFloat());
361  }
362 
363  return true;
364 }
365 
366 QString
368  QString uri)
369 {
370  QString str;
371  QTextStream s(&str);
372 
373  // assumes the usual prefixes are available; requires that uri be
374  // a local fragment (e.g. ":transform") rather than a uri enclosed
375  // in <>, so that we can suffix it if need be
376 
377  QString pluginId = transform.getPluginIdentifier();
378  QString pluginUri = PluginRDFIndexer::getInstance()->getURIForPluginId(pluginId);
379 
380  if (pluginUri != "") {
381  s << uri << " a vamp:Transform ;" << endl;
382  s << " vamp:plugin <" << QUrl(pluginUri).toEncoded().data() << "> ;" << endl;
383  } else {
384  cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No plugin URI available for plugin id \"" << pluginId << "\", writing synthetic plugin and library resources" << endl;
385  QString type, soname, label;
386  PluginIdentifier::parseIdentifier(pluginId, type, soname, label);
387  s << uri << "_plugin a vamp:Plugin ;" << endl;
388  s << " vamp:identifier \"" << label << "\" .\n" << endl;
389  s << uri << "_library a vamp:PluginLibrary ;" << endl;
390  s << " vamp:identifier \"" << soname << "\" ;" << endl;
391  s << " vamp:available_plugin " << uri << "_plugin .\n" << endl;
392  s << uri << " a vamp:Transform ;" << endl;
393  s << " vamp:plugin " << uri << "_plugin ;" << endl;
394  }
395 
396  PluginRDFDescription description(pluginId);
397  QString outputId = transform.getOutput();
398  QString outputUri = description.getOutputUri(outputId);
399 
400  if (transform.getOutput() != "" && outputUri == "") {
401  cerr << "WARNING: RDFTransformFactory::writeTransformToRDF: No output URI available for transform output id \"" << transform.getOutput() << "\", writing a synthetic output resource" << endl;
402  }
403 
404  if (transform.getStepSize() != 0) {
405  s << " vamp:step_size \"" << transform.getStepSize() << "\"^^xsd:int ; " << endl;
406  }
407  if (transform.getBlockSize() != 0) {
408  s << " vamp:block_size \"" << transform.getBlockSize() << "\"^^xsd:int ; " << endl;
409  }
410  if (transform.getWindowType() != HanningWindow) {
411  s << " vamp:window_type \"" <<
412  Window<float>::getNameForType(transform.getWindowType()).c_str()
413  << "\" ; " << endl;
414  }
415  if (transform.getStartTime() != RealTime::zeroTime) {
416  s << " vamp:start \"" << transform.getStartTime().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
417  }
418  if (transform.getDuration() != RealTime::zeroTime) {
419  s << " vamp:duration \"" << transform.getDuration().toXsdDuration().c_str() << "\"^^xsd:duration ; " << endl;
420  }
421  if (transform.getSampleRate() != 0) {
422  s << " vamp:sample_rate \"" << transform.getSampleRate() << "\"^^xsd:float ; " << endl;
423  }
424  if (transform.getPluginVersion() != "") {
425  s << " vamp:plugin_version \"\"\"" << transform.getPluginVersion() << "\"\"\" ; " << endl;
426  }
427 
428  QString program = transform.getProgram();
429  if (program != "") {
430  s << " vamp:program \"\"\"" << program << "\"\"\" ;" << endl;
431  }
432 
433  QString summary = transform.summaryTypeToString(transform.getSummaryType());
434  if (summary != "") {
435  s << " vamp:summary_type \"" << summary << "\" ;" << endl;
436  }
437 
438  Transform::ParameterMap parameters = transform.getParameters();
439  for (Transform::ParameterMap::const_iterator i = parameters.begin();
440  i != parameters.end(); ++i) {
441  QString name = i->first;
442  float value = i->second;
443  s << " vamp:parameter_binding [" << endl;
444  s << " vamp:parameter [ vamp:identifier \"" << name << "\" ] ;" << endl;
445  s << " vamp:value \"" << value << "\"^^xsd:float ;" << endl;
446  s << " ] ;" << endl;
447  }
448 
449  if (outputUri != "") {
450  s << " vamp:output <" << QUrl(outputUri).toEncoded().data() << "> ." << endl;
451  } else if (outputId != "") {
452  s << " vamp:output [ vamp:identifier \"" << outputId << "\" ] ." << endl;
453  } else {
454  s << " ." << endl;
455  }
456 
457  return str;
458 }
459 
sv_samplerate_t getSampleRate() const
Definition: Transform.cpp:378
std::vector< Transform > getTransforms(ProgressReporter *)
QString getOutput() const
Definition: Transform.cpp:219
QString getURIForPluginId(QString pluginId)
int getStepSize() const
Definition: Transform.cpp:318
void setDuration(RealTime d)
Definition: Transform.cpp:372
QString getErrorString() const
Return any error string resulting from loading or querying the file.
static std::string getNameForType(WindowType type)
Definition: Window.h:189
RealTime getDuration() const
Definition: Transform.cpp:366
static QString getKnownExtensions()
void setSampleRate(sv_samplerate_t rate)
Definition: Transform.cpp:384
void setWindowType(WindowType type)
Definition: Transform.cpp:348
Definition: Window.h:43
const ParameterMap & getParameters() const
Definition: Transform.cpp:244
QString getIdForPluginURI(QString uri)
void setPluginVersion(QString version)
Definition: Transform.cpp:288
std::string toXsdDuration() const
Return a string in xsd:duration format.
Definition: RealTimeSV.cpp:424
static void parseIdentifier(QString identifier, QString &type, QString &soName, QString &label)
bool isOK()
isOK() may be queried at any point after getTransforms() has been called.
void setStartTime(RealTime t)
Definition: Transform.cpp:360
QString getProgram() const
Definition: Transform.cpp:294
virtual QString toXmlString(QString indent="", QString extraAttributes="") const
Convert this exportable object to XML in a string.
WindowType getWindowType() const
Definition: Transform.cpp:342
bool setParameters(Transform &, QString)
const Dataquay::BasicStore * getIndex()
void setOutput(QString output)
Definition: Transform.cpp:231
void setPluginIdentifier(QString pluginIdentifier)
Definition: Transform.cpp:225
bool setOutput(Transform &, QString)
static QString writeTransformToRDF(const Transform &, QString uri)
RDFTransformFactoryImpl * m_d
bool isRDF()
isRDF() may be queried at any point after construction.
void setBlockSize(int s)
Definition: Transform.cpp:336
RDFTransformFactory(QString url)
std::map< QString, float > ParameterMap
Definition: Transform.h:86
std::vector< Transform > getTransforms(ProgressReporter *reporter)
QString getPluginVersion() const
Definition: Transform.cpp:282
static SummaryType stringToSummaryType(QString)
Definition: Transform.cpp:445
void setSummaryType(SummaryType type)
Definition: Transform.cpp:312
SummaryType getSummaryType() const
Definition: Transform.cpp:306
void setParameter(QString name, float value)
Definition: Transform.cpp:256
static PluginRDFIndexer * getInstance()
QString getPluginIdentifier() const
Definition: Transform.cpp:213
static QString writeTransformToRDF(const Transform &, QString)
void setProgram(QString program)
Definition: Transform.cpp:300
static const RealTime zeroTime
Definition: RealTime.h:204
static RealTime fromXsdDuration(std::string xsdd)
Definition: RealTimeSV.cpp:96
QString getOutputUri(QString outputId) const
RealTime getStartTime() const
Definition: Transform.cpp:354
static QString summaryTypeToString(SummaryType)
Definition: Transform.cpp:465
void setStepSize(int s)
Definition: Transform.cpp:324
int getBlockSize() const
Definition: Transform.cpp:330
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
Definition: RealTime.h:42