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 "PluginRDFDescription.h"
|
Chris@439
|
17
|
Chris@439
|
18 #include "PluginRDFIndexer.h"
|
Chris@439
|
19 #include "SimpleSPARQLQuery.h"
|
Chris@439
|
20
|
Chris@457
|
21 #include "data/fileio/FileSource.h"
|
Chris@468
|
22 #include "data/fileio/CachedFile.h"
|
Chris@457
|
23
|
Chris@457
|
24 #include "base/Profiler.h"
|
Chris@457
|
25
|
Chris@439
|
26 #include "plugin/PluginIdentifier.h"
|
Chris@439
|
27
|
Chris@439
|
28 #include <iostream>
|
Chris@439
|
29 using std::cerr;
|
Chris@439
|
30 using std::endl;
|
Chris@439
|
31
|
Chris@439
|
32 PluginRDFDescription::PluginRDFDescription(QString pluginId) :
|
Chris@468
|
33 //!!! m_source(0),
|
Chris@439
|
34 m_pluginId(pluginId),
|
Chris@439
|
35 m_haveDescription(false)
|
Chris@439
|
36 {
|
Chris@439
|
37 PluginRDFIndexer *indexer = PluginRDFIndexer::getInstance();
|
Chris@439
|
38 QString url = indexer->getDescriptionURLForPluginId(pluginId);
|
Chris@439
|
39 if (url == "") {
|
Chris@439
|
40 cerr << "PluginRDFDescription: WARNING: No RDF description available for plugin ID \""
|
Chris@439
|
41 << pluginId.toStdString() << "\"" << endl;
|
Chris@439
|
42 } else {
|
Chris@439
|
43 if (!indexURL(url)) {
|
Chris@439
|
44 cerr << "PluginRDFDescription: ERROR: Failed to query RDF description for plugin ID \""
|
Chris@439
|
45 << pluginId.toStdString() << "\"" << endl;
|
Chris@439
|
46 } else {
|
Chris@439
|
47 m_haveDescription = true;
|
Chris@439
|
48 }
|
Chris@439
|
49 }
|
Chris@439
|
50 }
|
Chris@439
|
51
|
Chris@439
|
52 PluginRDFDescription::~PluginRDFDescription()
|
Chris@439
|
53 {
|
Chris@468
|
54 //!!! delete m_source;
|
Chris@439
|
55 }
|
Chris@439
|
56
|
Chris@439
|
57 bool
|
Chris@439
|
58 PluginRDFDescription::haveDescription() const
|
Chris@439
|
59 {
|
Chris@439
|
60 return m_haveDescription;
|
Chris@439
|
61 }
|
Chris@439
|
62
|
Chris@457
|
63 QString
|
Chris@457
|
64 PluginRDFDescription::getPluginName() const
|
Chris@457
|
65 {
|
Chris@457
|
66 return m_pluginName;
|
Chris@457
|
67 }
|
Chris@457
|
68
|
Chris@457
|
69 QString
|
Chris@457
|
70 PluginRDFDescription::getPluginDescription() const
|
Chris@457
|
71 {
|
Chris@457
|
72 return m_pluginDescription;
|
Chris@457
|
73 }
|
Chris@457
|
74
|
Chris@457
|
75 QString
|
Chris@457
|
76 PluginRDFDescription::getPluginMaker() const
|
Chris@457
|
77 {
|
Chris@457
|
78 return m_pluginMaker;
|
Chris@457
|
79 }
|
Chris@457
|
80
|
Chris@462
|
81 QString
|
Chris@462
|
82 PluginRDFDescription::getPluginInfoURL() const
|
Chris@462
|
83 {
|
Chris@462
|
84 return m_pluginInfoURL;
|
Chris@462
|
85 }
|
Chris@462
|
86
|
Chris@457
|
87 QStringList
|
Chris@457
|
88 PluginRDFDescription::getOutputIds() const
|
Chris@457
|
89 {
|
Chris@457
|
90 QStringList ids;
|
Chris@457
|
91 for (OutputDispositionMap::const_iterator i = m_outputDispositions.begin();
|
Chris@457
|
92 i != m_outputDispositions.end(); ++i) {
|
Chris@457
|
93 ids.push_back(i->first);
|
Chris@457
|
94 }
|
Chris@457
|
95 return ids;
|
Chris@457
|
96 }
|
Chris@457
|
97
|
Chris@457
|
98 QString
|
Chris@457
|
99 PluginRDFDescription::getOutputName(QString outputId) const
|
Chris@457
|
100 {
|
Chris@457
|
101 if (m_outputNames.find(outputId) == m_outputNames.end()) {
|
Chris@457
|
102 return "";
|
Chris@457
|
103 }
|
Chris@457
|
104 return m_outputNames.find(outputId)->second;
|
Chris@457
|
105 }
|
Chris@457
|
106
|
Chris@439
|
107 PluginRDFDescription::OutputDisposition
|
Chris@439
|
108 PluginRDFDescription::getOutputDisposition(QString outputId) const
|
Chris@439
|
109 {
|
Chris@439
|
110 if (m_outputDispositions.find(outputId) == m_outputDispositions.end()) {
|
Chris@439
|
111 return OutputDispositionUnknown;
|
Chris@439
|
112 }
|
Chris@439
|
113 return m_outputDispositions.find(outputId)->second;
|
Chris@439
|
114 }
|
Chris@439
|
115
|
Chris@439
|
116 QString
|
Chris@439
|
117 PluginRDFDescription::getOutputEventTypeURI(QString outputId) const
|
Chris@439
|
118 {
|
Chris@439
|
119 if (m_outputEventTypeURIMap.find(outputId) ==
|
Chris@439
|
120 m_outputEventTypeURIMap.end()) {
|
Chris@439
|
121 return "";
|
Chris@439
|
122 }
|
Chris@439
|
123 return m_outputEventTypeURIMap.find(outputId)->second;
|
Chris@439
|
124 }
|
Chris@439
|
125
|
Chris@439
|
126 QString
|
Chris@440
|
127 PluginRDFDescription::getOutputFeatureAttributeURI(QString outputId) const
|
Chris@440
|
128 {
|
Chris@440
|
129 if (m_outputFeatureAttributeURIMap.find(outputId) ==
|
Chris@440
|
130 m_outputFeatureAttributeURIMap.end()) {
|
Chris@440
|
131 return "";
|
Chris@440
|
132 }
|
Chris@440
|
133 return m_outputFeatureAttributeURIMap.find(outputId)->second;
|
Chris@440
|
134 }
|
Chris@440
|
135
|
Chris@440
|
136 QString
|
Chris@440
|
137 PluginRDFDescription::getOutputSignalTypeURI(QString outputId) const
|
Chris@440
|
138 {
|
Chris@440
|
139 if (m_outputSignalTypeURIMap.find(outputId) ==
|
Chris@440
|
140 m_outputSignalTypeURIMap.end()) {
|
Chris@440
|
141 return "";
|
Chris@440
|
142 }
|
Chris@440
|
143 return m_outputSignalTypeURIMap.find(outputId)->second;
|
Chris@440
|
144 }
|
Chris@440
|
145
|
Chris@440
|
146 QString
|
Chris@439
|
147 PluginRDFDescription::getOutputUnit(QString outputId) const
|
Chris@439
|
148 {
|
Chris@439
|
149 if (m_outputUnitMap.find(outputId) == m_outputUnitMap.end()) {
|
Chris@439
|
150 return "";
|
Chris@439
|
151 }
|
Chris@439
|
152 return m_outputUnitMap.find(outputId)->second;
|
Chris@439
|
153 }
|
Chris@439
|
154
|
Chris@439
|
155 bool
|
Chris@439
|
156 PluginRDFDescription::indexURL(QString url)
|
Chris@439
|
157 {
|
Chris@457
|
158 Profiler profiler("PluginRDFDescription::indexURL");
|
Chris@457
|
159
|
Chris@439
|
160 QString type, soname, label;
|
Chris@439
|
161 PluginIdentifier::parseIdentifier(m_pluginId, type, soname, label);
|
Chris@439
|
162
|
Chris@457
|
163 bool success = true;
|
Chris@457
|
164
|
Chris@457
|
165 QString local = url;
|
Chris@457
|
166
|
Chris@457
|
167 if (FileSource::isRemote(url) &&
|
Chris@457
|
168 FileSource::canHandleScheme(url)) {
|
Chris@461
|
169
|
Chris@461
|
170 //!!! persistent with expiry
|
Chris@457
|
171
|
Chris@468
|
172 CachedFile cf(url);
|
Chris@468
|
173 if (!cf.isOK()) {
|
Chris@468
|
174 return false;
|
Chris@468
|
175 }
|
Chris@468
|
176
|
Chris@468
|
177 local = QUrl::fromLocalFile(cf.getLocalFilename()).toString();
|
Chris@468
|
178 /*!!!
|
Chris@461
|
179 m_source = new FileSource(url, 0, FileSource::PersistentCache);
|
Chris@461
|
180
|
Chris@457
|
181 if (!m_source->isAvailable()) {
|
Chris@457
|
182 delete m_source;
|
Chris@457
|
183 m_source = 0;
|
Chris@457
|
184 return false;
|
Chris@457
|
185 }
|
Chris@457
|
186 m_source->waitForData();
|
Chris@457
|
187 local = QUrl::fromLocalFile(m_source->getLocalFilename()).toString();
|
Chris@468
|
188 */
|
Chris@457
|
189 }
|
Chris@457
|
190
|
Chris@457
|
191 if (!indexMetadata(local, label)) success = false;
|
Chris@457
|
192 if (!indexOutputs(local, label)) success = false;
|
Chris@457
|
193
|
Chris@457
|
194 return success;
|
Chris@457
|
195 }
|
Chris@457
|
196
|
Chris@457
|
197 bool
|
Chris@457
|
198 PluginRDFDescription::indexMetadata(QString url, QString label)
|
Chris@457
|
199 {
|
Chris@457
|
200 Profiler profiler("PluginRDFDescription::indexMetadata");
|
Chris@457
|
201
|
Chris@457
|
202 QString queryTemplate =
|
Chris@457
|
203 QString(
|
Chris@457
|
204 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@457
|
205 " PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
|
Chris@457
|
206 " PREFIX dc: <http://purl.org/dc/elements/1.1/> "
|
Chris@457
|
207 " SELECT ?%4 FROM <%1> "
|
Chris@457
|
208 " WHERE { "
|
Chris@457
|
209 " ?plugin a vamp:Plugin ; "
|
Chris@457
|
210 " vamp:identifier \"%2\" ; "
|
Chris@457
|
211 " %3 ?%4 . "
|
Chris@457
|
212 " }")
|
Chris@457
|
213 .arg(url)
|
Chris@457
|
214 .arg(label);
|
Chris@457
|
215
|
Chris@457
|
216 SimpleSPARQLQuery::Value v;
|
Chris@457
|
217
|
Chris@457
|
218 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@457
|
219 (queryTemplate.arg("vamp:name").arg("name"), "name");
|
Chris@457
|
220
|
Chris@457
|
221 if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") {
|
Chris@457
|
222 m_pluginName = v.value;
|
Chris@457
|
223 }
|
Chris@457
|
224
|
Chris@457
|
225 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@457
|
226 (queryTemplate.arg("dc:description").arg("description"), "description");
|
Chris@457
|
227
|
Chris@457
|
228 if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") {
|
Chris@457
|
229 m_pluginDescription = v.value;
|
Chris@457
|
230 }
|
Chris@457
|
231
|
Chris@457
|
232 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@457
|
233 (QString(
|
Chris@457
|
234 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@457
|
235 " PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
|
Chris@457
|
236 " SELECT ?name FROM <%1> "
|
Chris@457
|
237 " WHERE { "
|
Chris@457
|
238 " ?plugin a vamp:Plugin ; "
|
Chris@457
|
239 " vamp:identifier \"%2\" ; "
|
Chris@457
|
240 " foaf:maker ?maker . "
|
Chris@457
|
241 " ?maker foaf:name ?name . "
|
Chris@457
|
242 " }")
|
Chris@457
|
243 .arg(url)
|
Chris@457
|
244 .arg(label), "name");
|
Chris@457
|
245
|
Chris@457
|
246 if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") {
|
Chris@457
|
247 m_pluginMaker = v.value;
|
Chris@457
|
248 }
|
Chris@457
|
249
|
Chris@462
|
250 // If we have a more-information URL for this plugin, then we take
|
Chris@463
|
251 // that. Otherwise, a more-information URL for the plugin
|
Chris@462
|
252 // library would do nicely. Failing that, we could perhaps use
|
Chris@462
|
253 // any foaf:page URL at all that appears in the file -- but
|
Chris@462
|
254 // perhaps that would be unwise
|
Chris@462
|
255
|
Chris@462
|
256 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@462
|
257 (QString(
|
Chris@462
|
258 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@462
|
259 " PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
|
Chris@462
|
260 " SELECT ?page from <%1> "
|
Chris@462
|
261 " WHERE { "
|
Chris@462
|
262 " ?plugin a vamp:Plugin ; "
|
Chris@462
|
263 " vamp:identifier \"%2\" ; "
|
Chris@462
|
264 " foaf:page ?page . "
|
Chris@462
|
265 " }")
|
Chris@462
|
266 .arg(url)
|
Chris@462
|
267 .arg(label), "page");
|
Chris@462
|
268
|
Chris@462
|
269 if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") {
|
Chris@462
|
270
|
Chris@462
|
271 m_pluginInfoURL = v.value;
|
Chris@462
|
272
|
Chris@462
|
273 } else {
|
Chris@462
|
274
|
Chris@462
|
275 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@462
|
276 (QString(
|
Chris@462
|
277 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@462
|
278 " PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
|
Chris@462
|
279 " SELECT ?page from <%1> "
|
Chris@462
|
280 " WHERE { "
|
Chris@462
|
281 " ?library a vamp:PluginLibrary ; "
|
Chris@462
|
282 " vamp:available_plugin ?plugin ; "
|
Chris@462
|
283 " foaf:page ?page . "
|
Chris@462
|
284 " ?plugin a vamp:Plugin ; "
|
Chris@462
|
285 " vamp:identifier \"%2\" . "
|
Chris@462
|
286 " }")
|
Chris@462
|
287 .arg(url)
|
Chris@462
|
288 .arg(label), "page");
|
Chris@462
|
289
|
Chris@462
|
290 if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") {
|
Chris@462
|
291
|
Chris@462
|
292 m_pluginInfoURL = v.value;
|
Chris@462
|
293 }
|
Chris@462
|
294 }
|
Chris@462
|
295
|
Chris@457
|
296 return true;
|
Chris@457
|
297 }
|
Chris@457
|
298
|
Chris@457
|
299 bool
|
Chris@457
|
300 PluginRDFDescription::indexOutputs(QString url, QString label)
|
Chris@457
|
301 {
|
Chris@457
|
302 Profiler profiler("PluginRDFDescription::indexOutputs");
|
Chris@457
|
303
|
Chris@439
|
304 SimpleSPARQLQuery query
|
Chris@439
|
305 (QString
|
Chris@439
|
306 (
|
Chris@439
|
307 " PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@439
|
308
|
Chris@440
|
309 " SELECT ?output ?output_id ?output_type ?unit "
|
Chris@439
|
310 " FROM <%1> "
|
Chris@439
|
311
|
Chris@439
|
312 " WHERE { "
|
Chris@439
|
313
|
Chris@439
|
314 " ?plugin a vamp:Plugin ; "
|
Chris@439
|
315 " vamp:identifier \"%2\" ; "
|
Chris@440
|
316 " vamp:output ?output . "
|
Chris@439
|
317
|
Chris@439
|
318 " ?output vamp:identifier ?output_id ; "
|
Chris@439
|
319 " a ?output_type . "
|
Chris@439
|
320
|
Chris@439
|
321 " OPTIONAL { "
|
Chris@439
|
322 " ?output vamp:unit ?unit "
|
Chris@439
|
323 " } . "
|
Chris@439
|
324
|
Chris@439
|
325 " } "
|
Chris@439
|
326 )
|
Chris@439
|
327 .arg(url)
|
Chris@439
|
328 .arg(label));
|
Chris@439
|
329
|
Chris@439
|
330 SimpleSPARQLQuery::ResultList results = query.execute();
|
Chris@439
|
331
|
Chris@439
|
332 if (!query.isOK()) {
|
Chris@439
|
333 cerr << "ERROR: PluginRDFDescription::indexURL: ERROR: Failed to query document at <"
|
Chris@439
|
334 << url.toStdString() << ">: "
|
Chris@439
|
335 << query.getErrorString().toStdString() << endl;
|
Chris@439
|
336 return false;
|
Chris@439
|
337 }
|
Chris@439
|
338
|
Chris@439
|
339 if (results.empty()) {
|
Chris@439
|
340 cerr << "ERROR: PluginRDFDescription::indexURL: NOTE: Document at <"
|
Chris@439
|
341 << url.toStdString()
|
Chris@440
|
342 << "> does not appear to describe any outputs for plugin with id \""
|
Chris@440
|
343 << label.toStdString() << "\"" << endl;
|
Chris@439
|
344 return false;
|
Chris@439
|
345 }
|
Chris@439
|
346
|
Chris@439
|
347 // Note that an output may appear more than once, if it inherits
|
Chris@439
|
348 // more than one type (e.g. DenseOutput and QuantizedOutput). So
|
Chris@439
|
349 // these results must accumulate
|
Chris@439
|
350
|
Chris@439
|
351 for (int i = 0; i < results.size(); ++i) {
|
Chris@439
|
352
|
Chris@440
|
353 QString outputUri = results[i]["output"].value;
|
Chris@439
|
354 QString outputId = results[i]["output_id"].value;
|
Chris@439
|
355 QString outputType = results[i]["output_type"].value;
|
Chris@439
|
356
|
Chris@439
|
357 if (outputType.contains("DenseOutput")) {
|
Chris@439
|
358 m_outputDispositions[outputId] = OutputDense;
|
Chris@439
|
359 } else if (outputType.contains("SparseOutput")) {
|
Chris@439
|
360 m_outputDispositions[outputId] = OutputSparse;
|
Chris@439
|
361 } else if (outputType.contains("TrackLevelOutput")) {
|
Chris@439
|
362 m_outputDispositions[outputId] = OutputTrackLevel;
|
Chris@457
|
363 } else {
|
Chris@457
|
364 m_outputDispositions[outputId] = OutputDispositionUnknown;
|
Chris@439
|
365 }
|
Chris@439
|
366
|
Chris@439
|
367 if (results[i]["unit"].type == SimpleSPARQLQuery::LiteralValue) {
|
Chris@439
|
368
|
Chris@439
|
369 QString unit = results[i]["unit"].value;
|
Chris@439
|
370
|
Chris@439
|
371 if (unit != "") {
|
Chris@439
|
372 m_outputUnitMap[outputId] = unit;
|
Chris@439
|
373 }
|
Chris@439
|
374 }
|
Chris@440
|
375
|
Chris@457
|
376 SimpleSPARQLQuery::Value v;
|
Chris@457
|
377
|
Chris@457
|
378 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@457
|
379 (QString(" PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@457
|
380 " PREFIX dc: <http://purl.org/dc/elements/1.1/> "
|
Chris@457
|
381 " SELECT ?title FROM <%1> "
|
Chris@457
|
382 " WHERE { <%2> dc:title ?title } ")
|
Chris@457
|
383 .arg(url).arg(outputUri), "title");
|
Chris@457
|
384
|
Chris@457
|
385 if (v.type == SimpleSPARQLQuery::LiteralValue && v.value != "") {
|
Chris@457
|
386 m_outputNames[outputId] = v.value;
|
Chris@457
|
387 }
|
Chris@457
|
388
|
Chris@440
|
389 QString queryTemplate =
|
Chris@440
|
390 QString(" PREFIX vamp: <http://purl.org/ontology/vamp/> "
|
Chris@440
|
391 " SELECT ?%3 FROM <%1> "
|
Chris@440
|
392 " WHERE { <%2> vamp:computes_%3 ?%3 } ")
|
Chris@440
|
393 .arg(url).arg(outputUri);
|
Chris@440
|
394
|
Chris@440
|
395 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@440
|
396 (queryTemplate.arg("event_type"), "event_type");
|
Chris@440
|
397
|
Chris@440
|
398 if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") {
|
Chris@440
|
399 m_outputEventTypeURIMap[outputId] = v.value;
|
Chris@440
|
400 }
|
Chris@440
|
401
|
Chris@440
|
402 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@440
|
403 (queryTemplate.arg("feature_attribute"), "feature_attribute");
|
Chris@440
|
404
|
Chris@440
|
405 if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") {
|
Chris@440
|
406 m_outputFeatureAttributeURIMap[outputId] = v.value;
|
Chris@440
|
407 }
|
Chris@440
|
408
|
Chris@440
|
409 v = SimpleSPARQLQuery::singleResultQuery
|
Chris@440
|
410 (queryTemplate.arg("signal_type"), "signal_type");
|
Chris@440
|
411
|
Chris@440
|
412 if (v.type == SimpleSPARQLQuery::URIValue && v.value != "") {
|
Chris@440
|
413 m_outputSignalTypeURIMap[outputId] = v.value;
|
Chris@440
|
414 }
|
Chris@439
|
415 }
|
Chris@439
|
416
|
Chris@439
|
417 return true;
|
Chris@439
|
418 }
|
Chris@439
|
419
|