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 "RDFTransformFactory.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 #include "PluginRDFIndexer.h"
|
Chris@439
|
26 #include "base/ProgressReporter.h"
|
Chris@439
|
27
|
Chris@439
|
28 #include "transform/TransformFactory.h"
|
Chris@439
|
29
|
Chris@439
|
30 using std::cerr;
|
Chris@439
|
31 using std::endl;
|
Chris@439
|
32
|
Chris@439
|
33 typedef const unsigned char *STR; // redland's expected string type
|
Chris@439
|
34
|
Chris@439
|
35
|
Chris@439
|
36 class RDFTransformFactoryImpl
|
Chris@439
|
37 {
|
Chris@439
|
38 public:
|
Chris@439
|
39 RDFTransformFactoryImpl(QString url);
|
Chris@439
|
40 virtual ~RDFTransformFactoryImpl();
|
Chris@439
|
41
|
Chris@439
|
42 bool isOK();
|
Chris@439
|
43 QString getErrorString() const;
|
Chris@439
|
44
|
Chris@439
|
45 std::vector<Transform> getTransforms(ProgressReporter *);
|
Chris@439
|
46
|
Chris@439
|
47 protected:
|
Chris@439
|
48 QString m_urlString;
|
Chris@439
|
49 QString m_errorString;
|
Chris@440
|
50 bool setOutput(Transform &, QString, QString);
|
Chris@440
|
51 bool setParameters(Transform &, QString, QString);
|
Chris@439
|
52 };
|
Chris@439
|
53
|
Chris@439
|
54
|
Chris@439
|
55 QString
|
Chris@439
|
56 RDFTransformFactory::getKnownExtensions()
|
Chris@439
|
57 {
|
Chris@439
|
58 return "*.rdf *.n3 *.ttl";
|
Chris@439
|
59 }
|
Chris@439
|
60
|
Chris@439
|
61 RDFTransformFactory::RDFTransformFactory(QString url) :
|
Chris@439
|
62 m_d(new RDFTransformFactoryImpl(url))
|
Chris@439
|
63 {
|
Chris@439
|
64 }
|
Chris@439
|
65
|
Chris@439
|
66 RDFTransformFactory::~RDFTransformFactory()
|
Chris@439
|
67 {
|
Chris@439
|
68 delete m_d;
|
Chris@439
|
69 }
|
Chris@439
|
70
|
Chris@439
|
71 bool
|
Chris@439
|
72 RDFTransformFactory::isOK()
|
Chris@439
|
73 {
|
Chris@439
|
74 return m_d->isOK();
|
Chris@439
|
75 }
|
Chris@439
|
76
|
Chris@439
|
77 QString
|
Chris@439
|
78 RDFTransformFactory::getErrorString() const
|
Chris@439
|
79 {
|
Chris@439
|
80 return m_d->getErrorString();
|
Chris@439
|
81 }
|
Chris@439
|
82
|
Chris@439
|
83 std::vector<Transform>
|
Chris@439
|
84 RDFTransformFactory::getTransforms(ProgressReporter *r)
|
Chris@439
|
85 {
|
Chris@439
|
86 return m_d->getTransforms(r);
|
Chris@439
|
87 }
|
Chris@439
|
88
|
Chris@439
|
89 RDFTransformFactoryImpl::RDFTransformFactoryImpl(QString url) :
|
Chris@439
|
90 m_urlString(url)
|
Chris@439
|
91 {
|
Chris@439
|
92 }
|
Chris@439
|
93
|
Chris@439
|
94 RDFTransformFactoryImpl::~RDFTransformFactoryImpl()
|
Chris@439
|
95 {
|
Chris@439
|
96 }
|
Chris@439
|
97
|
Chris@439
|
98 bool
|
Chris@439
|
99 RDFTransformFactoryImpl::isOK()
|
Chris@439
|
100 {
|
Chris@439
|
101 return (m_errorString == "");
|
Chris@439
|
102 }
|
Chris@439
|
103
|
Chris@439
|
104 QString
|
Chris@439
|
105 RDFTransformFactoryImpl::getErrorString() const
|
Chris@439
|
106 {
|
Chris@439
|
107 return m_errorString;
|
Chris@439
|
108 }
|
Chris@439
|
109
|
Chris@439
|
110 std::vector<Transform>
|
Chris@439
|
111 RDFTransformFactoryImpl::getTransforms(ProgressReporter *reporter)
|
Chris@439
|
112 {
|
Chris@439
|
113 std::vector<Transform> transforms;
|
Chris@439
|
114
|
Chris@440
|
115 // We have to do this a very long way round, to work around
|
Chris@440
|
116 // rasqal's current inability to handle correctly more than one
|
Chris@440
|
117 // OPTIONAL graph in a query
|
Chris@439
|
118
|
Chris@440
|
119 const char *optionals[] = {
|
Chris@440
|
120 "output",
|
Chris@440
|
121 "program",
|
Chris@440
|
122 "step_size",
|
Chris@440
|
123 "block_size",
|
Chris@440
|
124 "window_type",
|
Chris@440
|
125 "sample_rate",
|
Chris@440
|
126 "start",
|
Chris@440
|
127 "duration"
|
Chris@440
|
128 };
|
Chris@439
|
129
|
Chris@440
|
130 std::map<QString, Transform> uriTransformMap;
|
Chris@439
|
131
|
Chris@440
|
132 QString queryTemplate =
|
Chris@440
|
133 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@439
|
134
|
Chris@440
|
135 " SELECT ?transform ?plugin %1 "
|
Chris@440
|
136
|
Chris@440
|
137 " FROM <%2> "
|
Chris@439
|
138
|
Chris@440
|
139 " WHERE { "
|
Chris@440
|
140 " ?transform a vamp:Transform ; "
|
Chris@440
|
141 " vamp:plugin ?plugin . "
|
Chris@440
|
142 " %3 "
|
Chris@440
|
143 " } ";
|
Chris@440
|
144
|
Chris@440
|
145 SimpleSPARQLQuery transformsQuery
|
Chris@440
|
146 (queryTemplate.arg("").arg(m_urlString).arg(""));
|
Chris@440
|
147
|
Chris@440
|
148 SimpleSPARQLQuery::ResultList transformResults = transformsQuery.execute();
|
Chris@440
|
149
|
Chris@440
|
150 if (!transformsQuery.isOK()) {
|
Chris@440
|
151 m_errorString = transformsQuery.getErrorString();
|
Chris@439
|
152 return transforms;
|
Chris@439
|
153 }
|
Chris@439
|
154
|
Chris@440
|
155 if (transformResults.empty()) {
|
Chris@440
|
156 cerr << "RDFTransformFactory: NOTE: No RDF/TTL transform descriptions found in document at <" << m_urlString.toStdString() << ">" << endl;
|
Chris@439
|
157 return transforms;
|
Chris@439
|
158 }
|
Chris@439
|
159
|
Chris@439
|
160 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
|
Chris@439
|
161
|
Chris@440
|
162 for (int i = 0; i < transformResults.size(); ++i) {
|
Chris@439
|
163
|
Chris@440
|
164 SimpleSPARQLQuery::KeyValueMap &result = transformResults[i];
|
Chris@439
|
165
|
Chris@439
|
166 QString transformUri = result["transform"].value;
|
Chris@439
|
167 QString pluginUri = result["plugin"].value;
|
Chris@439
|
168
|
Chris@439
|
169 QString pluginId = indexer->getIdForPluginURI(pluginUri);
|
Chris@439
|
170 if (pluginId == "") {
|
Chris@439
|
171 cerr << "RDFTransformFactory: WARNING: Unknown plugin <"
|
Chris@439
|
172 << pluginUri.toStdString() << "> for transform <"
|
Chris@440
|
173 << transformUri.toStdString() << ">, skipping this transform"
|
Chris@440
|
174 << endl;
|
Chris@440
|
175 continue;
|
Chris@440
|
176 }
|
Chris@440
|
177
|
Chris@440
|
178 QString pluginDescriptionURL =
|
Chris@440
|
179 indexer->getDescriptionURLForPluginId(pluginId);
|
Chris@440
|
180 if (pluginDescriptionURL == "") {
|
Chris@440
|
181 cerr << "RDFTransformFactory: WARNING: No RDF description available for plugin <"
|
Chris@440
|
182 << pluginUri.toStdString() << ">, skipping transform <"
|
Chris@439
|
183 << transformUri.toStdString() << ">" << endl;
|
Chris@439
|
184 continue;
|
Chris@439
|
185 }
|
Chris@439
|
186
|
Chris@439
|
187 Transform transform;
|
Chris@439
|
188 transform.setPluginIdentifier(pluginId);
|
Chris@439
|
189
|
Chris@440
|
190 if (!setOutput(transform, transformUri, pluginDescriptionURL)) {
|
Chris@439
|
191 return transforms;
|
Chris@439
|
192 }
|
Chris@439
|
193
|
Chris@440
|
194 if (!setParameters(transform, transformUri, pluginDescriptionURL)) {
|
Chris@439
|
195 return transforms;
|
Chris@439
|
196 }
|
Chris@439
|
197
|
Chris@440
|
198 uriTransformMap[transformUri] = transform;
|
Chris@440
|
199 }
|
Chris@439
|
200
|
Chris@440
|
201 for (int i = 0; i < sizeof(optionals)/sizeof(optionals[0]); ++i) {
|
Chris@439
|
202
|
Chris@440
|
203 QString optional = optionals[i];
|
Chris@439
|
204
|
Chris@440
|
205 SimpleSPARQLQuery query
|
Chris@440
|
206 (queryTemplate
|
Chris@440
|
207 .arg(QString("?%1").arg(optional))
|
Chris@440
|
208 .arg(m_urlString)
|
Chris@440
|
209 .arg(QString("?transform vamp:%1 ?%2")
|
Chris@440
|
210 .arg(optionals[i]).arg(optional)));
|
Chris@440
|
211
|
Chris@440
|
212 SimpleSPARQLQuery::ResultList results = query.execute();
|
Chris@440
|
213
|
Chris@440
|
214 if (!query.isOK()) {
|
Chris@440
|
215 m_errorString = query.getErrorString();
|
Chris@440
|
216 return transforms;
|
Chris@439
|
217 }
|
Chris@439
|
218
|
Chris@440
|
219 if (results.empty()) continue;
|
Chris@440
|
220
|
Chris@440
|
221 for (int j = 0; j < results.size(); ++j) {
|
Chris@440
|
222
|
Chris@440
|
223 QString transformUri = results[j]["transform"].value;
|
Chris@440
|
224
|
Chris@440
|
225 if (uriTransformMap.find(transformUri) == uriTransformMap.end()) {
|
Chris@440
|
226 cerr << "RDFTransformFactory: ERROR: Transform URI <"
|
Chris@440
|
227 << transformUri.toStdString() << "> not found in internal map!" << endl;
|
Chris@440
|
228 continue;
|
Chris@440
|
229 }
|
Chris@440
|
230
|
Chris@440
|
231 Transform &transform = uriTransformMap[transformUri];
|
Chris@440
|
232 const SimpleSPARQLQuery::Value &v = results[j][optional];
|
Chris@440
|
233
|
Chris@440
|
234 if (v.type == SimpleSPARQLQuery::LiteralValue) {
|
Chris@440
|
235
|
Chris@440
|
236 if (optional == "program") {
|
Chris@440
|
237 transform.setProgram(v.value);
|
Chris@440
|
238 } else if (optional == "step_size") {
|
Chris@440
|
239 transform.setStepSize(v.value.toUInt());
|
Chris@440
|
240 } else if (optional == "block_size") {
|
Chris@440
|
241 transform.setBlockSize(v.value.toUInt());
|
Chris@440
|
242 } else if (optional == "window_type") {
|
Chris@440
|
243 cerr << "NOTE: can't handle window type yet (value is \""
|
Chris@440
|
244 << v.value.toStdString() << "\")" << endl;
|
Chris@440
|
245 } else if (optional == "sample_rate") {
|
Chris@440
|
246 transform.setSampleRate(v.value.toFloat());
|
Chris@440
|
247 } else if (optional == "start") {
|
Chris@440
|
248 transform.setStartTime
|
Chris@440
|
249 (RealTime::fromXsdDuration(v.value.toStdString()));
|
Chris@440
|
250 } else if (optional == "duration") {
|
Chris@440
|
251 transform.setDuration
|
Chris@440
|
252 (RealTime::fromXsdDuration(v.value.toStdString()));
|
Chris@440
|
253 } else {
|
Chris@440
|
254 cerr << "RDFTransformFactory: ERROR: Inconsistent optionals lists (unexpected optional \"" << optional.toStdString() << "\"" << endl;
|
Chris@440
|
255 }
|
Chris@440
|
256 }
|
Chris@440
|
257 }
|
Chris@440
|
258 }
|
Chris@440
|
259
|
Chris@440
|
260 for (std::map<QString, Transform>::iterator i = uriTransformMap.begin();
|
Chris@440
|
261 i != uriTransformMap.end(); ++i) {
|
Chris@440
|
262
|
Chris@440
|
263 Transform &transform = i->second;
|
Chris@440
|
264
|
Chris@439
|
265 cerr << "RDFTransformFactory: NOTE: Transform is: " << endl;
|
Chris@439
|
266 cerr << transform.toXmlString().toStdString() << endl;
|
Chris@439
|
267
|
Chris@439
|
268 transforms.push_back(transform);
|
Chris@439
|
269 }
|
Chris@439
|
270
|
Chris@439
|
271 return transforms;
|
Chris@439
|
272 }
|
Chris@439
|
273
|
Chris@440
|
274 bool
|
Chris@440
|
275 RDFTransformFactoryImpl::setOutput(Transform &transform,
|
Chris@440
|
276 QString transformUri,
|
Chris@440
|
277 QString pluginDescriptionURL)
|
Chris@440
|
278 {
|
Chris@440
|
279 SimpleSPARQLQuery outputQuery
|
Chris@440
|
280 (QString
|
Chris@440
|
281 (
|
Chris@440
|
282 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@440
|
283
|
Chris@440
|
284 " SELECT ?output_id "
|
Chris@440
|
285
|
Chris@440
|
286 " FROM <%1> "
|
Chris@440
|
287 " FROM <%2> "
|
Chris@440
|
288
|
Chris@440
|
289 " WHERE { "
|
Chris@440
|
290 " <%3> vamp:output ?output . "
|
Chris@440
|
291 " ?output vamp:identifier ?output_id "
|
Chris@440
|
292 " } "
|
Chris@440
|
293 )
|
Chris@440
|
294 .arg(m_urlString)
|
Chris@440
|
295 .arg(pluginDescriptionURL)
|
Chris@440
|
296 .arg(transformUri));
|
Chris@440
|
297
|
Chris@440
|
298 SimpleSPARQLQuery::ResultList outputResults = outputQuery.execute();
|
Chris@440
|
299
|
Chris@440
|
300 if (!outputQuery.isOK()) {
|
Chris@440
|
301 m_errorString = outputQuery.getErrorString();
|
Chris@440
|
302 return false;
|
Chris@440
|
303 }
|
Chris@440
|
304
|
Chris@440
|
305 if (outputQuery.wasCancelled()) {
|
Chris@440
|
306 m_errorString = "Query cancelled";
|
Chris@440
|
307 return false;
|
Chris@440
|
308 }
|
Chris@440
|
309
|
Chris@440
|
310 for (int j = 0; j < outputResults.size(); ++j) {
|
Chris@440
|
311 QString outputId = outputResults[j]["output_id"].value;
|
Chris@440
|
312 transform.setOutput(outputId);
|
Chris@440
|
313 }
|
Chris@440
|
314
|
Chris@440
|
315 return true;
|
Chris@440
|
316 }
|
Chris@440
|
317
|
Chris@440
|
318
|
Chris@440
|
319 bool
|
Chris@440
|
320 RDFTransformFactoryImpl::setParameters(Transform &transform,
|
Chris@440
|
321 QString transformUri,
|
Chris@440
|
322 QString pluginDescriptionURL)
|
Chris@440
|
323 {
|
Chris@440
|
324 SimpleSPARQLQuery paramQuery
|
Chris@440
|
325 (QString
|
Chris@440
|
326 (
|
Chris@440
|
327 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@440
|
328
|
Chris@440
|
329 " SELECT ?param_id ?param_value "
|
Chris@440
|
330
|
Chris@440
|
331 " FROM <%1> "
|
Chris@440
|
332 " FROM <%2> "
|
Chris@440
|
333
|
Chris@440
|
334 " WHERE { "
|
Chris@440
|
335 " <%3> vamp:parameter_binding ?binding . "
|
Chris@440
|
336 " ?binding vamp:parameter ?param ; "
|
Chris@440
|
337 " vamp:value ?param_value . "
|
Chris@440
|
338 " ?param vamp:identifier ?param_id "
|
Chris@440
|
339 " } "
|
Chris@440
|
340 )
|
Chris@440
|
341 .arg(m_urlString)
|
Chris@440
|
342 .arg(pluginDescriptionURL)
|
Chris@440
|
343 .arg(transformUri));
|
Chris@440
|
344
|
Chris@440
|
345 SimpleSPARQLQuery::ResultList paramResults = paramQuery.execute();
|
Chris@440
|
346
|
Chris@440
|
347 if (!paramQuery.isOK()) {
|
Chris@440
|
348 m_errorString = paramQuery.getErrorString();
|
Chris@440
|
349 return false;
|
Chris@440
|
350 }
|
Chris@440
|
351
|
Chris@440
|
352 if (paramQuery.wasCancelled()) {
|
Chris@440
|
353 m_errorString = "Query cancelled";
|
Chris@440
|
354 return false;
|
Chris@440
|
355 }
|
Chris@440
|
356
|
Chris@440
|
357 for (int j = 0; j < paramResults.size(); ++j) {
|
Chris@440
|
358
|
Chris@440
|
359 QString paramId = paramResults[j]["param_id"].value;
|
Chris@440
|
360 QString paramValue = paramResults[j]["param_value"].value;
|
Chris@440
|
361
|
Chris@440
|
362 if (paramId == "" || paramValue == "") continue;
|
Chris@440
|
363
|
Chris@440
|
364 transform.setParameter(paramId, paramValue.toFloat());
|
Chris@440
|
365 }
|
Chris@440
|
366
|
Chris@440
|
367 return true;
|
Chris@440
|
368 }
|
Chris@440
|
369
|