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