RDFFeatureWriter.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 Annotator
5  A utility for batch feature extraction from audio files.
6  Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
7  Copyright 2007-2008 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 <fstream>
17 
18 #include "base/Exceptions.h"
19 
20 #include "RDFFeatureWriter.h"
21 #include "RDFTransformFactory.h"
22 #include "PluginRDFIndexer.h"
23 
24 #include <QTextStream>
25 #include <QTextCodec>
26 #include <QUrl>
27 #include <QFileInfo>
28 #include <QRegExp>
29 
30 using namespace std;
31 using Vamp::Plugin;
32 using Vamp::PluginBase;
33 
35  FileFeatureWriter(SupportOneFilePerTrackTransform |
36  SupportOneFilePerTrack |
37  SupportOneFileTotal |
38  SupportStdOut,
39  "n3"),
40  m_plain(false),
41  m_network(false),
42  m_networkRetrieved(false),
43  m_count(0)
44 {
45 }
46 
48 {
49 }
50 
51 string
53 {
54  return "Write output in Audio Features Ontology RDF/Turtle format.";
55 }
56 
59 {
61  Parameter p;
62 
63  p.name = "plain";
64  p.description = "Use \"plain\" RDF even if transform metadata is available.";
65  p.hasArg = false;
66  pl.push_back(p);
67 
68  p.name = "audiofile-uri";
69  p.description = "Link the output RDF to the given audio file URI instead of its actual location.";
70  p.hasArg = true;
71  pl.push_back(p);
72 
73  p.name = "track-uri";
74  p.description = "Link the output RDF to the given track URI.";
75  p.hasArg = true;
76  pl.push_back(p);
77 
78  p.name = "maker-uri";
79  p.description = "Link the track in the output RDF to the given foaf:maker URI.";
80  p.hasArg = true;
81  pl.push_back(p);
82 
83  p.name = "network";
84  p.description = "Attempt to retrieve RDF descriptions of plugins from network, if not available locally";
85  p.hasArg = false;
86  pl.push_back(p);
87 
88  return pl;
89 }
90 
91 void
92 RDFFeatureWriter::setParameters(map<string, string> &params)
93 {
95 
96  for (map<string, string>::iterator i = params.begin();
97  i != params.end(); ++i) {
98  if (i->first == "plain") {
99  m_plain = true;
100  }
101  if (i->first == "audiofile-uri") {
102  m_userAudioFileUri = i->second.c_str();
103  }
104  if (i->first == "track-uri") {
105  m_userTrackUri = i->second.c_str();
106  }
107  if (i->first == "maker-uri") {
108  m_userMakerUri = i->second.c_str();
109  }
110  if (i->first == "network") {
111  m_network = true;
112  }
113  }
114 }
115 
116 void
118  TrackMetadata metadata)
119 {
120 // cerr << "setTrackMetadata: title = " << metadata.title << ", maker = " << metadata.maker << endl;
121  m_metadata[trackId] = metadata;
122 }
123 
124 void
126 {
127  m_fixedEventTypeURI = uri;
128 }
129 
130 void
131 RDFFeatureWriter::write(QString trackId,
132  const Transform &transform,
133  const Plugin::OutputDescriptor& output,
134  const Plugin::FeatureList& features,
135  std::string summaryType)
136 {
137  QString pluginId = transform.getPluginIdentifier();
138 
139  if (m_rdfDescriptions.find(pluginId) == m_rdfDescriptions.end()) {
140 
141  if (m_network && !m_networkRetrieved) {
143  m_networkRetrieved = true;
144  }
145 
146  m_rdfDescriptions[pluginId] = PluginRDFDescription(pluginId);
147 
148  if (m_rdfDescriptions[pluginId].haveDescription()) {
149  SVCERR << "NOTE: Have RDF description for plugin ID \""
150  << pluginId << "\"" << endl;
151  } else {
152  SVCERR << "NOTE: No RDF description for plugin ID \""
153  << pluginId << "\"" << endl;
154  if (!m_network) {
155  SVCERR << " Consider using the --rdf-network option to retrieve plugin descriptions" << endl;
156  SVCERR << " from the network where possible." << endl;
157  }
158  }
159  }
160 
161  // Need to select appropriate output file for our track/transform
162  // combination
163 
164  QTextStream *stream = getOutputStream(trackId, transform.getIdentifier(),
165  QTextCodec::codecForName("UTF-8"));
166  if (!stream) {
167  throw FailedToOpenOutputStream(trackId, transform.getIdentifier());
168  }
169 
170  if (m_startedStreamTransforms.find(stream) ==
172 // cerr << "This stream is new, writing prefixes" << endl;
173  writePrefixes(stream);
174  if (m_singleFileName == "" && !m_stdout) {
175  writeSignalDescription(stream, trackId);
176  }
177  }
178 
179  if (m_startedStreamTransforms[stream].find(transform) ==
180  m_startedStreamTransforms[stream].end()) {
181  m_startedStreamTransforms[stream].insert(transform);
183  (stream, transform, output, m_rdfDescriptions[pluginId],
184  summaryType);
185  }
186 
187  if (m_singleFileName != "" || m_stdout) {
188  if (m_startedTrackIds.find(trackId) == m_startedTrackIds.end()) {
189  writeSignalDescription(stream, trackId);
190  m_startedTrackIds.insert(trackId);
191  }
192  }
193 
194  QString timelineURI = m_trackTimelineURIs[trackId];
195 
196  if (timelineURI == "") {
197  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing features without having established a timeline URI!" << endl;
198  exit(1);
199  }
200 
201  if (summaryType != "") {
202 
203  writeSparseRDF(stream, transform, output, features,
204  m_rdfDescriptions[pluginId], timelineURI);
205 
206  } else if (m_rdfDescriptions[pluginId].haveDescription() &&
207  m_rdfDescriptions[pluginId].getOutputDisposition
208  (output.identifier.c_str()) ==
210 
211  QString signalURI = m_trackSignalURIs[trackId];
212 
213  if (signalURI == "") {
214  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having established a signal URI!" << endl;
215  exit(1);
216  }
217 
218  writeDenseRDF(stream, transform, output, features,
219  m_rdfDescriptions[pluginId], signalURI, timelineURI);
220 
221  } else if (!m_plain &&
222  m_rdfDescriptions[pluginId].haveDescription() &&
223  m_rdfDescriptions[pluginId].getOutputDisposition
224  (output.identifier.c_str()) ==
226  m_rdfDescriptions[pluginId].getOutputFeatureAttributeURI
227  (output.identifier.c_str()) != "") {
228 
229  QString signalURI = m_trackSignalURIs[trackId];
230 
231  if (signalURI == "") {
232  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing track-level features without having established a signal URI!" << endl;
233  exit(1);
234  }
235 
236  writeTrackLevelRDF(stream, transform, output, features,
237  m_rdfDescriptions[pluginId], signalURI);
238 
239  } else {
240 
241  writeSparseRDF(stream, transform, output, features,
242  m_rdfDescriptions[pluginId], timelineURI);
243  }
244 }
245 
246 void
248 {
249  QTextStream &stream = *sptr;
250 
251  stream << "@prefix dc: <http://purl.org/dc/elements/1.1/> .\n"
252  << "@prefix mo: <http://purl.org/ontology/mo/> .\n"
253  << "@prefix af: <http://purl.org/ontology/af/> .\n"
254  << "@prefix foaf: <http://xmlns.com/foaf/0.1/> . \n"
255  << "@prefix event: <http://purl.org/NET/c4dm/event.owl#> .\n"
256  << "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
257  << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
258  << "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n"
259  << "@prefix tl: <http://purl.org/NET/c4dm/timeline.owl#> .\n"
260  << "@prefix vamp: <http://purl.org/ontology/vamp/> .\n"
261  << "@prefix : <#> .\n\n";
262 }
263 
264 void
266 {
267  // Appending to an RDF file is tricky, because we need to ensure
268  // that our URIs differ from any already in the file. This is a
269  // dirty grubby low-rent way of doing that. This function is
270  // called by FileFeatureWriter::getOutputFile when in append mode.
271 
272 // cerr << "reviewFileForAppending(" << filename << ")" << endl;
273 
274  QFile file(filename);
275 
276  // just return, don't report failure -- function that called us will do that
277  if (!file.open(QIODevice::ReadOnly)) return;
278 
279  QTextStream in(&file);
280 
281  QRegExp localObjectUriWithDigits(":[^ ]+_([0-9]+) a ");
282 
283  while (!in.atEnd()) {
284  QString line = in.readLine();
285  if (line.length() > 120) { // probably data
286  continue;
287  }
288  if (localObjectUriWithDigits.indexIn(line) > -1) {
289  QString numeric = localObjectUriWithDigits.cap(1);
290  int number = numeric.toInt();
291  if (number >= m_count) m_count = number + 1;
292  }
293  }
294 
295  file.close();
296 }
297 
298 void
300  QString trackId)
301 {
302 // SVDEBUG << "RDFFeatureWriter::writeSignalDescription" << endl;
303 
304  QTextStream &stream = *sptr;
305 
306  /*
307  * Describe signal we're analysing (AudioFile, Signal, TimeLine, etc.)
308  */
309 
310  QUrl url(trackId, QUrl::StrictMode);
311  QString scheme = url.scheme().toLower();
312  bool local = (scheme == "" || scheme == "file" || scheme.length() == 1);
313 
314  if (local) {
315  if (scheme == "") {
316  url.setScheme("file");
317  url.setPath(QFileInfo(url.path()).absoluteFilePath());
318  } else if (scheme.length() == 1) { // DOS drive letter!
319  url.setScheme("file");
320  url.setPath(scheme + ":" + url.path());
321  }
322  }
323 
324  // Note reviewFileForAppending above (when opening in append mode)
325 
326  unsigned long signalCount = m_count++;
327 
328  if (m_trackSignalURIs.find(trackId) == m_trackSignalURIs.end()) {
329  m_trackSignalURIs[trackId] = QString(":signal_%1").arg(signalCount);
330  }
331  QString signalURI = m_trackSignalURIs[trackId];
332 
333  if (m_trackTrackURIs.find(trackId) == m_trackTrackURIs.end()) {
334  m_trackTrackURIs[trackId] = QString(":track_%1").arg(signalCount);
335  }
336  QString trackURI = m_trackTrackURIs[trackId];
337 
338  bool userSpecifiedTrack = false;
339  if (m_userTrackUri != "") {
340  trackURI = "<" + m_userTrackUri + ">";
341  m_trackTrackURIs[trackId] = trackURI;
342  userSpecifiedTrack = true;
343  }
344 
345  if (m_trackTimelineURIs.find(trackId) == m_trackTimelineURIs.end()) {
346  m_trackTimelineURIs[trackId] = QString(":signal_timeline_%1").arg(signalCount);
347  }
348  QString timelineURI = m_trackTimelineURIs[trackId];
349 
350  QString afURI = url.toEncoded().data();
351  if (m_userAudioFileUri != "") afURI = m_userAudioFileUri;
352 
353  bool wantTrack = (userSpecifiedTrack ||
354  (m_userMakerUri != "") ||
355  haveTitleArtistMetadata(trackId));
356 
357 // cerr << "wantTrack = " << wantTrack << " (userSpecifiedTrack = "
358 // << userSpecifiedTrack << ", m_userMakerUri = " << m_userMakerUri << ", have metadata = " << (m_metadata.find(trackId) != m_metadata.end()) << ")" << endl;
359 
360  if (wantTrack) {
361  // We only write a Track at all if we have some title/artist
362  // metadata to put in it, or if the user has requested a
363  // specific track URI. Otherwise we can't be sure that what
364  // we have is a Track, in the publication sense -- it may just
365  // be a fragment, a test file, whatever. Since we'd have no
366  // metadata to associate with our Track, the only effect of
367  // including a Track would be to assert that this was one,
368  // which is the one thing we wouldn't know...
369  TrackMetadata tm;
370  if (haveTitleArtistMetadata(trackId)) {
371  tm = m_metadata[trackId];
372  }
373  stream << trackURI << " a mo:Track ";
374  if (tm.title != "") {
375  stream << ";\n dc:title \"\"\"" << tm.title << "\"\"\" ";
376  }
377  if (m_userMakerUri != "") {
378  stream << ";\n foaf:maker <" << m_userMakerUri << "> ";
379  } else if (tm.maker != "") {
380  stream << ";\n foaf:maker [ a mo:MusicArtist; foaf:name \"\"\"" << tm.maker << "\"\"\" ] ";
381  }
382  if (afURI != "") {
383  stream << ";\n mo:available_as <" << afURI << "> ";
384  }
385  stream << ".\n\n";
386  }
387 
388  if (afURI != "") {
389  stream << "<" << afURI << "> a mo:AudioFile ;\n";
390  stream << " mo:encodes " << signalURI << ".\n\n";
391  }
392 
393  stream << signalURI << " a mo:Signal ;\n";
394 
395  stream << " mo:time [\n"
396  << " a tl:Interval ;\n"
397  << " tl:onTimeLine "
398  << timelineURI << "\n ] .\n\n";
399 
400  stream << timelineURI << " a tl:Timeline .\n\n";
401 }
402 
403 void
405  const Transform &transform,
406  const Plugin::OutputDescriptor &od,
407  PluginRDFDescription &desc,
408  std::string summaryType)
409 {
410  QString outputId = od.identifier.c_str();
411  QTextStream &stream = *sptr;
412 
413  // There is no "needFeatureType" for track-level outputs, because
414  // we can't meaningfully write a feature at all if we don't know
415  // what property to use for it. If the output is track level but
416  // there is no feature type given, we have to revert to events.
417 
418  bool needEventType = false;
419  bool needSignalType = false;
420 
422 
423  if (summaryType == "" &&
424  desc.getOutputDisposition(outputId) ==
426 
427  // no feature events, so may need signal type but won't need
428  // event type
429 
430  if (m_plain) {
431 
432  needSignalType = true;
433 
434  } else if (desc.getOutputSignalTypeURI(outputId) == "") {
435 
436  needSignalType = true;
437  }
438 
439  } else if (desc.getOutputDisposition(outputId) ==
441 
442  // see note above -- need to generate an event type if no
443  // feature type given, or if in plain mode
444 
445  if (m_plain) {
446 
447  needEventType = true;
448 
449  } else if (desc.getOutputFeatureAttributeURI(outputId) == "") {
450 
451  if (desc.getOutputEventTypeURI(outputId) == "") {
452 
453  needEventType = true;
454  }
455  }
456 
457  } else {
458 
459  // may need event type but won't need signal type
460 
461  if (m_plain) {
462 
463  needEventType = true;
464 
465  } else if (desc.getOutputEventTypeURI(outputId) == "") {
466 
467  needEventType = true;
468  }
469  }
470 
471  QString transformUri;
472  if (m_transformURIs.find(transform) != m_transformURIs.end()) {
473  transformUri = m_transformURIs[transform];
474  } else {
475  transformUri = QString(":transform_%1_%2").arg(m_count++).arg(outputId);
476  m_transformURIs[transform] = transformUri;
477  }
478 
479  if (transform.getIdentifier() != "") {
480  stream << endl
481  << RDFTransformFactory::writeTransformToRDF(transform, transformUri)
482  << endl;
483  }
484 
485  if (needEventType && m_fixedEventTypeURI == "") {
486 
487  QString uri;
488  if (m_syntheticEventTypeURIs.find(transform) !=
489  m_syntheticEventTypeURIs.end()) {
490  uri = m_syntheticEventTypeURIs[transform];
491  } else {
492  uri = QString(":event_type_%1").arg(m_count++);
493  m_syntheticEventTypeURIs[transform] = uri;
494  }
495 
496  stream << uri
497  << " rdfs:subClassOf event:Event ;" << endl
498  << " dc:title \"" << od.name.c_str() << "\" ;" << endl
499  << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
500  << " dc:description \"" << od.description.c_str() << "\" ."
501  << endl << endl;
502  }
503 
504  if (needSignalType) {
505 
506  QString uri;
507  if (m_syntheticSignalTypeURIs.find(transform) !=
509  uri = m_syntheticSignalTypeURIs[transform];
510  } else {
511  uri = QString(":signal_type_%1").arg(m_count++);
512  m_syntheticSignalTypeURIs[transform] = uri;
513  }
514 
515  stream << uri
516  << " rdfs:subClassOf af:Signal ;" << endl
517  << " dc:title \"" << od.name.c_str() << "\" ;" << endl
518  << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
519  << " dc:description \"" << od.description.c_str() << "\" ."
520  << endl << endl;
521  }
522 }
523 
524 void
526  const Transform &transform,
527  const Plugin::OutputDescriptor& od,
528  const Plugin::FeatureList& featureList,
529  PluginRDFDescription &desc,
530  QString timelineURI)
531 {
532 // SVDEBUG << "RDFFeatureWriter::writeSparseRDF: have " << featureList.size() << " features" << endl;
533 
534  if (featureList.empty()) return;
535  QTextStream &stream = *sptr;
536 
537  bool plain = (m_plain || !desc.haveDescription());
538 
539  QString outputId = od.identifier.c_str();
540 
541  // iterate through FeatureLists
542 
543  for (int i = 0; i < (int)featureList.size(); ++i) {
544 
545  const Plugin::Feature &feature = featureList[i];
546  unsigned long featureNumber = m_count++;
547 
548  stream << ":event_" << featureNumber << " a ";
549 
550  if (m_fixedEventTypeURI != "") {
551  stream << m_fixedEventTypeURI << " ;\n";
552  } else {
553  QString eventTypeURI = desc.getOutputEventTypeURI(outputId);
554  if (plain || eventTypeURI == "") {
555  if (m_syntheticEventTypeURIs.find(transform) !=
556  m_syntheticEventTypeURIs.end()) {
557  stream << m_syntheticEventTypeURIs[transform] << " ;\n";
558  } else {
559  stream << ":event_type_" << outputId << " ;\n";
560  }
561  } else {
562  stream << "<" << eventTypeURI << "> ;\n";
563  }
564  }
565 
566  QString timestamp = feature.timestamp.toString().c_str();
567  timestamp.replace(QRegExp("^ +"), "");
568 
569  if (feature.hasDuration && feature.duration > Vamp::RealTime::zeroTime) {
570 
571  QString duration = feature.duration.toString().c_str();
572  duration.replace(QRegExp("^ +"), "");
573 
574  stream << " event:time [ \n"
575  << " a tl:Interval ;\n"
576  << " tl:onTimeLine " << timelineURI << " ;\n"
577  << " tl:beginsAt \"PT" << timestamp
578  << "S\"^^xsd:duration ;\n"
579  << " tl:duration \"PT" << duration
580  << "S\"^^xsd:duration ;\n"
581  << " ] ";
582 
583  } else {
584 
585  stream << " event:time [ \n"
586  << " a tl:Instant ;\n" //location of the event in time
587  << " tl:onTimeLine " << timelineURI << " ;\n"
588  << " tl:at \"PT" << timestamp
589  << "S\"^^xsd:duration ;\n ] ";
590  }
591 
592  if (transform.getIdentifier() != "") {
593  stream << ";\n";
594  stream << " vamp:computed_by " << m_transformURIs[transform] << " ";
595  }
596 
597  if (feature.label.length() > 0) {
598  stream << ";\n";
599  stream << " rdfs:label \"\"\"" << feature.label.c_str() << "\"\"\" ";
600  }
601 
602  if (!feature.values.empty()) {
603  stream << ";\n";
605  stream << " af:feature \"" << feature.values[0];
606  for (int j = 1; j < (int)feature.values.size(); ++j) {
607  stream << " " << feature.values[j];
608  }
609  stream << "\" ";
610  }
611 
612  stream << ".\n";
613  }
614 }
615 
616 void
618  const Transform &,
619  const Plugin::OutputDescriptor& od,
620  const Plugin::FeatureList& featureList,
621  PluginRDFDescription &desc,
622  QString signalURI)
623 {
624  if (featureList.empty()) return;
625  QTextStream &stream = *sptr;
626 
627 // bool plain = (m_plain || !desc.haveDescription());
628 
629  QString outputId = od.identifier.c_str();
630  QString featureUri = desc.getOutputFeatureAttributeURI(outputId);
631 
632  if (featureUri == "") {
633  SVDEBUG << "RDFFeatureWriter::writeTrackLevelRDF: ERROR: No feature URI available -- this function should not have been called!" << endl;
634  return;
635  }
636 
637  for (int i = 0; i < (int)featureList.size(); ++i) {
638 
639  const Plugin::Feature &feature = featureList[i];
640 
641  if (feature.values.empty()) {
642 
643  if (feature.label == "") continue;
644 
645  stream << signalURI << " " << featureUri << " \"\"\""
646  << feature.label.c_str() << "\"\"\" .\n";
647 
648  } else {
649 
650  stream << signalURI << " " << featureUri << " \""
651  << feature.values[0] << "\"^^xsd:float .\n";
652  }
653  }
654 }
655 
656 void
658  const Transform &transform,
659  const Plugin::OutputDescriptor& od,
660  const Plugin::FeatureList& featureList,
661  PluginRDFDescription &desc,
662  QString signalURI,
663  QString timelineURI)
664 {
665  if (featureList.empty()) return;
666 
667  StringTransformPair sp(signalURI, transform);
668 
669  if (m_openDenseFeatures.find(sp) == m_openDenseFeatures.end()) {
670 
671  StreamBuffer b(sptr, "");
672  m_openDenseFeatures[sp] = b;
673 
674  QString &str(m_openDenseFeatures[sp].second);
675  QTextStream stream(&str);
676 
677  bool plain = (m_plain || !desc.haveDescription());
678  QString outputId = od.identifier.c_str();
679 
680  unsigned long featureNumber = m_count++;
681 
682  // need to write out feature timeline map -- for this we need
683  // the sample rate, window length and hop size from the
684  // transform
685 
686  stream << "\n:feature_timeline_" << featureNumber << " a tl:DiscreteTimeLine .\n\n";
687 
688  sv_samplerate_t sampleRate;
689  int stepSize, blockSize;
690 
691  // If the output is FixedSampleRate, we need to draw the
692  // sample rate and step size from the output descriptor;
693  // otherwise they come from the transform
694 
695  if (od.sampleType == Plugin::OutputDescriptor::FixedSampleRate) {
696 
697  sampleRate = od.sampleRate;
698  stepSize = 1;
699  blockSize = 1;
700 
701  } else {
702 
703  sampleRate = transform.getSampleRate();
704  if (sampleRate == 0.f) {
705  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the sample rate properly!" << endl;
706  return;
707  }
708 
709  stepSize = transform.getStepSize();
710  if (stepSize == 0) {
711  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the step size properly!" << endl;
712  return;
713  }
714 
715  blockSize = transform.getBlockSize();
716  if (blockSize == 0) {
717  SVCERR << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the block size properly!" << endl;
718  return;
719  }
720  }
721 
722  stream << ":feature_timeline_map_" << featureNumber
723  << " a tl:UniformSamplingWindowingMap ;\n"
724  << " tl:rangeTimeLine :feature_timeline_" << featureNumber << " ;\n"
725  << " tl:domainTimeLine " << timelineURI << " ;\n"
726  << " tl:sampleRate \"" << sampleRate << "\"^^xsd:float ;\n"
727  << " tl:windowLength \"" << blockSize << "\"^^xsd:int ;\n"
728  << " tl:hopSize \"" << stepSize << "\"^^xsd:int .\n\n";
729 
730  stream << signalURI << " af:signal_feature :feature_"
731  << featureNumber << " ." << endl << endl;
732 
733  stream << ":feature_" << featureNumber << " a ";
734 
735  QString signalTypeURI = desc.getOutputSignalTypeURI(outputId);
736  if (plain || signalTypeURI == "") {
737  if (m_syntheticSignalTypeURIs.find(transform) !=
739  stream << m_syntheticSignalTypeURIs[transform] << " ;\n";
740  } else {
741  stream << ":signal_type_" << outputId << " ;\n";
742  }
743  } else {
744  stream << "<" << signalTypeURI << "> ;\n";
745  }
746 
747  stream << " mo:time ["
748  << "\n a tl:Interval ;"
749  << "\n tl:onTimeLine :feature_timeline_" << featureNumber << " ;";
750 
751  RealTime startrt = transform.getStartTime();
752  RealTime durationrt = transform.getDuration();
753 
755  (startrt, sampleRate) / stepSize;
757  (durationrt, sampleRate) / stepSize;
758 
759  if (start != 0) {
760  stream << "\n tl:start \"" << start << "\"^^xsd:int ;";
761  }
762  if (duration != 0) {
763  stream << "\n tl:duration \"" << duration << "\"^^xsd:int ;";
764  }
765 
766  stream << "\n ] ;\n";
767 
768  if (transform.getIdentifier() != "") {
769  stream << " vamp:computed_by " << m_transformURIs[transform] << " ;\n";
770  }
771 
772  if (od.hasFixedBinCount) {
773  // We only know the height, so write the width as zero
774  stream << " af:dimensions \"" << od.binCount << " 0\" ;\n";
775  }
776 
777  stream << " af:value \"";
778  }
779 
780  QString &str = m_openDenseFeatures[sp].second;
781  QTextStream stream(&str);
782 
783  for (int i = 0; i < (int)featureList.size(); ++i) {
784 
785  const Plugin::Feature &feature = featureList[i];
786 
787  for (int j = 0; j < (int)feature.values.size(); ++j) {
788  stream << feature.values[j] << " ";
789  }
790  }
791 }
792 
794 {
795 // SVDEBUG << "RDFFeatureWriter::finish()" << endl;
796 
797  // close any open dense feature literals
798 
799  for (map<StringTransformPair, StreamBuffer>::iterator i =
800  m_openDenseFeatures.begin();
801  i != m_openDenseFeatures.end(); ++i) {
802 // SVDEBUG << "closing a stream" << endl;
803  StreamBuffer &b = i->second;
804  *(b.first) << b.second << "\" ." << endl;
805  }
806 
807  m_openDenseFeatures.clear();
809 
811 }
812 
813 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
sv_samplerate_t getSampleRate() const
Definition: Transform.cpp:378
void setTrackMetadata(QString trackid, TrackMetadata metadata) override
void writeLocalFeatureTypes(QTextStream *, const Transform &, const Vamp::Plugin::OutputDescriptor &, PluginRDFDescription &, std::string summaryType)
int getStepSize() const
Definition: Transform.cpp:318
RealTime getDuration() const
Definition: Transform.cpp:366
map< StringTransformPair, StreamBuffer > m_openDenseFeatures
pair< QTextStream *, QString > StreamBuffer
virtual void setFixedEventTypeURI(QString uri)
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
map< QTextStream *, set< Transform > > m_startedStreamTransforms
void finish() override
QTextStream * getOutputStream(QString, TransformId, QTextCodec *)
vector< Parameter > ParameterList
Definition: FeatureWriter.h:51
set< QString > m_startedTrackIds
void writeTrackLevelRDF(QTextStream *stream, const Transform &transform, const Vamp::Plugin::OutputDescriptor &output, const Vamp::Plugin::FeatureList &features, PluginRDFDescription &desc, QString signalURI)
map< Transform, QString > m_syntheticSignalTypeURIs
bool haveTitleArtistMetadata(QString trackId) const
map< QString, QString > m_trackTrackURIs
ParameterList getSupportedParameters() const override
pair< QString, Transform > StringTransformPair
QString getOutputFeatureAttributeURI(QString outputId) const
void writeSignalDescription(QTextStream *, QString)
QString getOutputSignalTypeURI(QString outputId) const
void setParameters(map< string, string > &params) override
RDFDescriptionMap m_rdfDescriptions
void writePrefixes(QTextStream *)
virtual ~RDFFeatureWriter()
static QString writeTransformToRDF(const Transform &, QString uri)
OutputDisposition getOutputDisposition(QString outputId) const
map< Transform, QString > m_transformURIs
QString getOutputEventTypeURI(QString outputId) const
static sv_frame_t realTime2Frame(const RealTime &r, sv_samplerate_t sampleRate)
Convert a RealTime into a sample frame at the given sample rate.
Definition: RealTimeSV.cpp:490
void reviewFileForAppending(QString filename) override
void writeSparseRDF(QTextStream *stream, const Transform &transform, const Vamp::Plugin::OutputDescriptor &output, const Vamp::Plugin::FeatureList &features, PluginRDFDescription &desc, QString timelineURI)
void setParameters(map< string, string > &params) override
map< QString, QString > m_trackSignalURIs
QString m_fixedEventTypeURI
#define SVDEBUG
Definition: Debug.h:106
string getDescription() const override
void finish() override
TransformId getIdentifier() const
Definition: Transform.cpp:179
#define SVCERR
Definition: Debug.h:109
bool indexConfiguredURLs()
Index all URLs obtained from index files defined in the current settings.
map< QString, QString > m_trackTimelineURIs
static PluginRDFIndexer * getInstance()
QString getPluginIdentifier() const
Definition: Transform.cpp:213
map< Transform, QString > m_syntheticEventTypeURIs
RealTime getStartTime() const
Definition: Transform.cpp:354
TrackMetadataMap m_metadata
ParameterList getSupportedParameters() const override
void write(QString trackid, const Transform &transform, const Vamp::Plugin::OutputDescriptor &output, const Vamp::Plugin::FeatureList &features, std::string summaryType="") override
void writeDenseRDF(QTextStream *stream, const Transform &transform, const Vamp::Plugin::OutputDescriptor &output, const Vamp::Plugin::FeatureList &features, PluginRDFDescription &desc, QString signalURI, QString timelineURI)
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