annotate rdf/RDFFeatureWriter.cpp @ 558:1d7ebc05157e

* Some fairly simplistic code to set up layer type properties based on RDF data about feature types (both when running transforms and when importing features from RDF files).
author Chris Cannam
date Thu, 12 Feb 2009 15:26:43 +0000
parents 1d3fc01edc03
children b3a87e81c761
rev   line source
Chris@498 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@498 2
Chris@498 3 /*
Chris@498 4 Sonic Annotator
Chris@498 5 A utility for batch feature extraction from audio files.
Chris@498 6 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
Chris@498 7 Copyright 2007-2008 QMUL.
Chris@498 8
Chris@498 9 This program is free software; you can redistribute it and/or
Chris@498 10 modify it under the terms of the GNU General Public License as
Chris@498 11 published by the Free Software Foundation; either version 2 of the
Chris@498 12 License, or (at your option) any later version. See the file
Chris@498 13 COPYING included with this distribution for more information.
Chris@498 14 */
Chris@498 15
Chris@498 16 #include <fstream>
Chris@498 17
Chris@498 18 #include "vamp-hostsdk/PluginHostAdapter.h"
Chris@498 19 #include "vamp-hostsdk/PluginLoader.h"
Chris@498 20
Chris@498 21 #include "RDFFeatureWriter.h"
Chris@498 22 #include "RDFTransformFactory.h"
Chris@498 23
Chris@498 24 #include <QTextStream>
Chris@498 25 #include <QUrl>
Chris@508 26 #include <QFileInfo>
Chris@498 27 #include <QRegExp>
Chris@498 28
Chris@498 29 using namespace std;
Chris@498 30 using Vamp::Plugin;
Chris@498 31 using Vamp::PluginBase;
Chris@498 32
Chris@498 33 RDFFeatureWriter::RDFFeatureWriter() :
Chris@498 34 FileFeatureWriter(SupportOneFilePerTrackTransform |
Chris@498 35 SupportOneFilePerTrack |
Chris@498 36 SupportOneFileTotal,
Chris@498 37 "n3"),
Chris@498 38 m_plain(false),
Chris@498 39 m_count(0)
Chris@498 40 {
Chris@498 41 }
Chris@498 42
Chris@498 43 RDFFeatureWriter::~RDFFeatureWriter()
Chris@498 44 {
Chris@498 45 }
Chris@498 46
Chris@498 47 RDFFeatureWriter::ParameterList
Chris@498 48 RDFFeatureWriter::getSupportedParameters() const
Chris@498 49 {
Chris@498 50 ParameterList pl = FileFeatureWriter::getSupportedParameters();
Chris@498 51 Parameter p;
Chris@498 52
Chris@498 53 p.name = "plain";
Chris@498 54 p.description = "Use \"plain\" RDF even if transform metadata is available.";
Chris@498 55 p.hasArg = false;
Chris@498 56 pl.push_back(p);
Chris@498 57
Chris@498 58 p.name = "signal-uri";
Chris@498 59 p.description = "Link the output RDF to the given signal URI.";
Chris@498 60 p.hasArg = true;
Chris@498 61 pl.push_back(p);
Chris@498 62
Chris@498 63 return pl;
Chris@498 64 }
Chris@498 65
Chris@498 66 void
Chris@498 67 RDFFeatureWriter::setParameters(map<string, string> &params)
Chris@498 68 {
Chris@498 69 FileFeatureWriter::setParameters(params);
Chris@498 70
Chris@498 71 for (map<string, string>::iterator i = params.begin();
Chris@498 72 i != params.end(); ++i) {
Chris@498 73 if (i->first == "plain") {
Chris@498 74 m_plain = true;
Chris@498 75 }
Chris@498 76 if (i->first == "signal-uri") {
Chris@498 77 m_suri = i->second.c_str();
Chris@498 78 }
Chris@498 79 }
Chris@498 80 }
Chris@498 81
Chris@504 82 void
Chris@504 83 RDFFeatureWriter::setTrackMetadata(QString trackId,
Chris@504 84 TrackMetadata metadata)
Chris@504 85 {
Chris@504 86 m_metadata[trackId] = metadata;
Chris@504 87 }
Chris@504 88
Chris@504 89 void
Chris@510 90 RDFFeatureWriter::setFixedEventTypeURI(QString uri)
Chris@510 91 {
Chris@510 92 m_fixedEventTypeURI = uri;
Chris@510 93 }
Chris@510 94
Chris@510 95 void
Chris@504 96 RDFFeatureWriter::write(QString trackId,
Chris@504 97 const Transform &transform,
Chris@504 98 const Plugin::OutputDescriptor& output,
Chris@504 99 const Plugin::FeatureList& features,
Chris@504 100 std::string summaryType)
Chris@498 101 {
Chris@498 102 QString pluginId = transform.getPluginIdentifier();
Chris@498 103
Chris@498 104 if (m_rdfDescriptions.find(pluginId) == m_rdfDescriptions.end()) {
Chris@498 105
Chris@498 106 m_rdfDescriptions[pluginId] = PluginRDFDescription(pluginId);
Chris@498 107
Chris@498 108 if (m_rdfDescriptions[pluginId].haveDescription()) {
Chris@498 109 cerr << "NOTE: Have RDF description for plugin ID \""
Chris@498 110 << pluginId.toStdString() << "\"" << endl;
Chris@498 111 } else {
Chris@498 112 cerr << "NOTE: Do not have RDF description for plugin ID \""
Chris@498 113 << pluginId.toStdString() << "\"" << endl;
Chris@498 114 }
Chris@498 115 }
Chris@498 116
Chris@498 117 // Need to select appropriate output file for our track/transform
Chris@498 118 // combination
Chris@498 119
Chris@498 120 QTextStream *stream = getOutputStream(trackId, transform.getIdentifier());
Chris@512 121 if (!stream) {
Chris@512 122 std::cerr << "RDFFeatureWriter::write: ERROR: No output stream for track id \""
Chris@512 123 << trackId.toStdString() << "\" and transform \""
Chris@512 124 << transform.getIdentifier().toStdString() << "\"" << std::endl;
Chris@513 125 exit(1);
Chris@512 126 }
Chris@498 127
Chris@498 128 if (m_startedStreamTransforms.find(stream) ==
Chris@498 129 m_startedStreamTransforms.end()) {
Chris@530 130 cerr << "This stream is new, writing prefixes" << endl;
Chris@498 131 writePrefixes(stream);
Chris@498 132 if (m_singleFileName == "" && !m_stdout) {
Chris@498 133 writeSignalDescription(stream, trackId);
Chris@498 134 }
Chris@498 135 }
Chris@498 136
Chris@498 137 if (m_startedStreamTransforms[stream].find(transform) ==
Chris@498 138 m_startedStreamTransforms[stream].end()) {
Chris@498 139 m_startedStreamTransforms[stream].insert(transform);
Chris@498 140 writeLocalFeatureTypes
Chris@498 141 (stream, transform, output, m_rdfDescriptions[pluginId]);
Chris@498 142 }
Chris@498 143
Chris@498 144 if (m_singleFileName != "" || m_stdout) {
Chris@498 145 if (m_startedTrackIds.find(trackId) == m_startedTrackIds.end()) {
Chris@498 146 writeSignalDescription(stream, trackId);
Chris@498 147 m_startedTrackIds.insert(trackId);
Chris@498 148 }
Chris@498 149 }
Chris@498 150
Chris@498 151 QString timelineURI = m_trackTimelineURIs[trackId];
Chris@498 152
Chris@498 153 if (timelineURI == "") {
Chris@498 154 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing features without having established a timeline URI!" << endl;
Chris@498 155 exit(1);
Chris@498 156 }
Chris@498 157
Chris@498 158 if (summaryType != "") {
Chris@498 159
Chris@498 160 writeSparseRDF(stream, transform, output, features,
Chris@498 161 m_rdfDescriptions[pluginId], timelineURI);
Chris@498 162
Chris@498 163 } else if (m_rdfDescriptions[pluginId].haveDescription() &&
Chris@498 164 m_rdfDescriptions[pluginId].getOutputDisposition
Chris@498 165 (output.identifier.c_str()) ==
Chris@498 166 PluginRDFDescription::OutputDense) {
Chris@498 167
Chris@498 168 QString signalURI = m_trackSignalURIs[trackId];
Chris@498 169
Chris@498 170 if (signalURI == "") {
Chris@498 171 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having established a signal URI!" << endl;
Chris@498 172 exit(1);
Chris@498 173 }
Chris@498 174
Chris@498 175 writeDenseRDF(stream, transform, output, features,
Chris@498 176 m_rdfDescriptions[pluginId], signalURI, timelineURI);
Chris@498 177
Chris@507 178 } else if (!m_plain &&
Chris@507 179 m_rdfDescriptions[pluginId].haveDescription() &&
Chris@507 180 m_rdfDescriptions[pluginId].getOutputDisposition
Chris@507 181 (output.identifier.c_str()) ==
Chris@507 182 PluginRDFDescription::OutputTrackLevel &&
Chris@507 183 m_rdfDescriptions[pluginId].getOutputFeatureAttributeURI
Chris@507 184 (output.identifier.c_str()) != "") {
Chris@507 185
Chris@507 186 QString signalURI = m_trackSignalURIs[trackId];
Chris@507 187
Chris@507 188 if (signalURI == "") {
Chris@507 189 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing track-level features without having established a signal URI!" << endl;
Chris@507 190 exit(1);
Chris@507 191 }
Chris@507 192
Chris@507 193 writeTrackLevelRDF(stream, transform, output, features,
Chris@507 194 m_rdfDescriptions[pluginId], signalURI);
Chris@507 195
Chris@498 196 } else {
Chris@498 197
Chris@498 198 writeSparseRDF(stream, transform, output, features,
Chris@498 199 m_rdfDescriptions[pluginId], timelineURI);
Chris@498 200 }
Chris@498 201 }
Chris@498 202
Chris@498 203 void
Chris@498 204 RDFFeatureWriter::writePrefixes(QTextStream *sptr)
Chris@498 205 {
Chris@498 206 QTextStream &stream = *sptr;
Chris@498 207
Chris@498 208 stream << "@prefix dc: <http://purl.org/dc/elements/1.1/> .\n"
Chris@498 209 << "@prefix mo: <http://purl.org/ontology/mo/> .\n"
Chris@498 210 << "@prefix af: <http://purl.org/ontology/af/> .\n"
Chris@504 211 << "@prefix foaf: <http://xmlns.com/foaf/0.1/> . \n"
Chris@498 212 << "@prefix event: <http://purl.org/NET/c4dm/event.owl#> .\n"
Chris@498 213 << "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
Chris@498 214 << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
Chris@498 215 << "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n"
Chris@498 216 << "@prefix tl: <http://purl.org/NET/c4dm/timeline.owl#> .\n"
Chris@498 217 << "@prefix vamp: <http://purl.org/ontology/vamp/> .\n"
Chris@498 218 << "@prefix : <#> .\n\n";
Chris@498 219 }
Chris@498 220
Chris@498 221 void
Chris@498 222 RDFFeatureWriter::writeSignalDescription(QTextStream *sptr,
Chris@498 223 QString trackId)
Chris@498 224 {
Chris@530 225 std::cerr << "RDFFeatureWriter::writeSignalDescription" << std::endl;
Chris@530 226
Chris@498 227 QTextStream &stream = *sptr;
Chris@498 228
Chris@498 229 /*
Chris@498 230 * Describe signal we're analysing (AudioFile, Signal, TimeLine, etc.)
Chris@498 231 */
Chris@498 232
Chris@498 233 QUrl url(trackId);
Chris@498 234 QString scheme = url.scheme().toLower();
Chris@498 235 bool local = (scheme == "" || scheme == "file" || scheme.length() == 1);
Chris@498 236
Chris@498 237 if (local) {
Chris@498 238 if (scheme == "") {
Chris@498 239 url.setScheme("file");
Chris@508 240 url.setPath(QFileInfo(url.path()).absoluteFilePath());
Chris@498 241 } else if (scheme.length() == 1) { // DOS drive letter!
Chris@498 242 url.setScheme("file");
Chris@498 243 url.setPath(scheme + ":" + url.path());
Chris@498 244 }
Chris@498 245 }
Chris@498 246
Chris@498 247 //!!! FIX: If we are appending, we need to start counting after
Chris@498 248 //all of the existing counts that are already in the file!
Chris@498 249
Chris@498 250 uint64_t signalCount = m_count++;
Chris@498 251
Chris@498 252 if (m_trackSignalURIs.find(trackId) == m_trackSignalURIs.end()) {
Chris@498 253 m_trackSignalURIs[trackId] = QString(":signal_%1").arg(signalCount);
Chris@498 254 }
Chris@498 255
Chris@498 256 if (m_suri != NULL) {
Chris@498 257 m_trackSignalURIs[trackId] = "<" + m_suri + ">";
Chris@498 258 }
Chris@498 259 QString signalURI = m_trackSignalURIs[trackId];
Chris@498 260
Chris@498 261 if (m_trackTimelineURIs.find(trackId) == m_trackTimelineURIs.end()) {
Chris@498 262 m_trackTimelineURIs[trackId] = QString(":signal_timeline_%1").arg(signalCount);
Chris@498 263 }
Chris@498 264 QString timelineURI = m_trackTimelineURIs[trackId];
Chris@498 265
Chris@500 266 if (trackId != "") {
Chris@500 267 stream << "\n<" << url.toEncoded().data() << "> a mo:AudioFile .\n\n";
Chris@500 268 }
Chris@500 269
Chris@500 270 stream << signalURI << " a mo:Signal ;\n";
Chris@500 271
Chris@500 272 if (trackId != "") {
Chris@500 273 stream << " mo:available_as <" << url.toEncoded().data()
Chris@500 274 << "> ;\n";
Chris@500 275 }
Chris@500 276
Chris@504 277 if (m_metadata.find(trackId) != m_metadata.end()) {
Chris@504 278 TrackMetadata tm = m_metadata[trackId];
Chris@504 279 if (tm.title != "") {
Chris@504 280 stream << " dc:title \"\"\"" << tm.title << "\"\"\" ;\n";
Chris@504 281 }
Chris@504 282 if (tm.maker != "") {
Chris@507 283 stream << " foaf:maker [ a mo:MusicArtist; foaf:name \"\"\"" << tm.maker << "\"\"\" ] ;\n";
Chris@504 284 }
Chris@504 285 }
Chris@504 286
Chris@500 287 stream << " mo:time [\n"
Chris@498 288 << " a tl:Interval ;\n"
Chris@498 289 << " tl:onTimeLine "
Chris@498 290 << timelineURI << "\n ] .\n\n";
Chris@498 291 }
Chris@498 292
Chris@498 293 void
Chris@498 294 RDFFeatureWriter::writeLocalFeatureTypes(QTextStream *sptr,
Chris@498 295 const Transform &transform,
Chris@498 296 const Plugin::OutputDescriptor &od,
Chris@498 297 PluginRDFDescription &desc)
Chris@498 298 {
Chris@498 299 QString outputId = od.identifier.c_str();
Chris@498 300 QTextStream &stream = *sptr;
Chris@498 301
Chris@507 302 // There is no "needFeatureType" for track-level outputs, because
Chris@507 303 // we can't meaningfully write a feature at all if we don't know
Chris@507 304 // what property to use for it. If the output is track level but
Chris@507 305 // there is no feature type given, we have to revert to events.
Chris@507 306
Chris@498 307 bool needEventType = false;
Chris@498 308 bool needSignalType = false;
Chris@498 309
Chris@498 310 //!!! bin names, extents and so on can be written out using e.g. vamp:bin_names ( "a" "b" "c" )
Chris@498 311
Chris@498 312 if (desc.getOutputDisposition(outputId) ==
Chris@498 313 PluginRDFDescription::OutputDense) {
Chris@498 314
Chris@498 315 // no feature events, so may need signal type but won't need
Chris@498 316 // event type
Chris@498 317
Chris@498 318 if (m_plain) {
Chris@498 319
Chris@498 320 needSignalType = true;
Chris@498 321
Chris@498 322 } else if (desc.getOutputSignalTypeURI(outputId) == "") {
Chris@498 323
Chris@498 324 needSignalType = true;
Chris@498 325 }
Chris@498 326
Chris@507 327 } else if (desc.getOutputDisposition(outputId) ==
Chris@507 328 PluginRDFDescription::OutputTrackLevel) {
Chris@507 329
Chris@507 330 // see note above -- need to generate an event type if no
Chris@507 331 // feature type given, or if in plain mode
Chris@507 332
Chris@507 333 if (m_plain) {
Chris@507 334
Chris@507 335 needEventType = true;
Chris@507 336
Chris@507 337 } else if (desc.getOutputFeatureAttributeURI(outputId) == "") {
Chris@507 338
Chris@507 339 if (desc.getOutputEventTypeURI(outputId) == "") {
Chris@507 340
Chris@507 341 needEventType = true;
Chris@507 342 }
Chris@507 343 }
Chris@507 344
Chris@498 345 } else {
Chris@498 346
Chris@498 347 // may need event type but won't need signal type
Chris@498 348
Chris@498 349 if (m_plain) {
Chris@498 350
Chris@498 351 needEventType = true;
Chris@498 352
Chris@498 353 } else if (desc.getOutputEventTypeURI(outputId) == "") {
Chris@498 354
Chris@498 355 needEventType = true;
Chris@498 356 }
Chris@498 357 }
Chris@498 358
Chris@498 359 QString transformUri;
Chris@498 360 if (m_transformURIs.find(transform) != m_transformURIs.end()) {
Chris@498 361 transformUri = m_transformURIs[transform];
Chris@498 362 } else {
Chris@498 363 transformUri = QString(":transform_%1_%2").arg(m_count++).arg(outputId);
Chris@498 364 m_transformURIs[transform] = transformUri;
Chris@498 365 }
Chris@498 366
Chris@500 367 if (transform.getIdentifier() != "") {
Chris@508 368 stream << endl
Chris@508 369 << RDFTransformFactory::writeTransformToRDF(transform, transformUri)
Chris@500 370 << endl;
Chris@500 371 }
Chris@498 372
Chris@510 373 if (needEventType && m_fixedEventTypeURI == "") {
Chris@498 374
Chris@498 375 QString uri;
Chris@498 376 if (m_syntheticEventTypeURIs.find(transform) !=
Chris@498 377 m_syntheticEventTypeURIs.end()) {
Chris@498 378 uri = m_syntheticEventTypeURIs[transform];
Chris@498 379 } else {
Chris@498 380 uri = QString(":event_type_%1").arg(m_count++);
Chris@498 381 m_syntheticEventTypeURIs[transform] = uri;
Chris@498 382 }
Chris@498 383
Chris@498 384 stream << uri
Chris@498 385 << " rdfs:subClassOf event:Event ;" << endl
Chris@498 386 << " dc:title \"" << od.name.c_str() << "\" ;" << endl
Chris@498 387 << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
Chris@498 388 << " dc:description \"" << od.description.c_str() << "\" ."
Chris@498 389 << endl << endl;
Chris@498 390 }
Chris@498 391
Chris@498 392 if (needSignalType) {
Chris@498 393
Chris@498 394 QString uri;
Chris@498 395 if (m_syntheticSignalTypeURIs.find(transform) !=
Chris@498 396 m_syntheticSignalTypeURIs.end()) {
Chris@498 397 uri = m_syntheticSignalTypeURIs[transform];
Chris@498 398 } else {
Chris@498 399 uri = QString(":signal_type_%1").arg(m_count++);
Chris@498 400 m_syntheticSignalTypeURIs[transform] = uri;
Chris@498 401 }
Chris@498 402
Chris@498 403 stream << uri
Chris@498 404 << " rdfs:subClassOf af:Signal ;" << endl
Chris@498 405 << " dc:title \"" << od.name.c_str() << "\" ;" << endl
Chris@498 406 << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
Chris@498 407 << " dc:description \"" << od.description.c_str() << "\" ."
Chris@498 408 << endl << endl;
Chris@498 409 }
Chris@498 410 }
Chris@498 411
Chris@498 412 void
Chris@498 413 RDFFeatureWriter::writeSparseRDF(QTextStream *sptr,
Chris@498 414 const Transform &transform,
Chris@498 415 const Plugin::OutputDescriptor& od,
Chris@498 416 const Plugin::FeatureList& featureList,
Chris@498 417 PluginRDFDescription &desc,
Chris@498 418 QString timelineURI)
Chris@498 419 {
Chris@512 420 // std::cerr << "RDFFeatureWriter::writeSparseRDF: have " << featureList.size() << " features" << std::endl;
Chris@512 421
Chris@498 422 if (featureList.empty()) return;
Chris@498 423 QTextStream &stream = *sptr;
Chris@498 424
Chris@498 425 bool plain = (m_plain || !desc.haveDescription());
Chris@498 426
Chris@498 427 QString outputId = od.identifier.c_str();
Chris@498 428
Chris@498 429 // iterate through FeatureLists
Chris@498 430
Chris@498 431 for (int i = 0; i < featureList.size(); ++i) {
Chris@498 432
Chris@498 433 const Plugin::Feature &feature = featureList[i];
Chris@498 434 uint64_t featureNumber = m_count++;
Chris@498 435
Chris@498 436 stream << ":event_" << featureNumber << " a ";
Chris@498 437
Chris@510 438 if (m_fixedEventTypeURI != "") {
Chris@510 439 stream << m_fixedEventTypeURI << " ;\n";
Chris@510 440 } else {
Chris@510 441 QString eventTypeURI = desc.getOutputEventTypeURI(outputId);
Chris@510 442 if (plain || eventTypeURI == "") {
Chris@510 443 if (m_syntheticEventTypeURIs.find(transform) !=
Chris@510 444 m_syntheticEventTypeURIs.end()) {
Chris@510 445 stream << m_syntheticEventTypeURIs[transform] << " ;\n";
Chris@510 446 } else {
Chris@510 447 stream << ":event_type_" << outputId << " ;\n";
Chris@510 448 }
Chris@498 449 } else {
Chris@510 450 stream << "<" << eventTypeURI << "> ;\n";
Chris@498 451 }
Chris@498 452 }
Chris@498 453
Chris@498 454 QString timestamp = feature.timestamp.toString().c_str();
Chris@498 455 timestamp.replace(QRegExp("^ +"), "");
Chris@498 456
Chris@498 457 if (feature.hasDuration && feature.duration > Vamp::RealTime::zeroTime) {
Chris@498 458
Chris@498 459 QString duration = feature.duration.toString().c_str();
Chris@498 460 duration.replace(QRegExp("^ +"), "");
Chris@498 461
Chris@498 462 stream << " event:time [ \n"
Chris@498 463 << " a tl:Interval ;\n"
Chris@498 464 << " tl:onTimeLine " << timelineURI << " ;\n"
Chris@498 465 << " tl:beginsAt \"PT" << timestamp
Chris@498 466 << "S\"^^xsd:duration ;\n"
Chris@498 467 << " tl:duration \"PT" << duration
Chris@498 468 << "S\"^^xsd:duration ;\n"
Chris@498 469 << " ] ";
Chris@498 470
Chris@498 471 } else {
Chris@498 472
Chris@498 473 stream << " event:time [ \n"
Chris@498 474 << " a tl:Instant ;\n" //location of the event in time
Chris@498 475 << " tl:onTimeLine " << timelineURI << " ;\n"
Chris@498 476 << " tl:at \"PT" << timestamp
Chris@498 477 << "S\"^^xsd:duration ;\n ] ";
Chris@498 478 }
Chris@498 479
Chris@500 480 if (transform.getIdentifier() != "") {
Chris@500 481 stream << ";\n";
Chris@500 482 stream << " vamp:computed_by " << m_transformURIs[transform] << " ";
Chris@500 483 }
Chris@498 484
Chris@498 485 if (feature.label.length() > 0) {
Chris@498 486 stream << ";\n";
Chris@510 487 stream << " rdfs:label \"\"\"" << feature.label.c_str() << "\"\"\" ";
Chris@498 488 }
Chris@498 489
Chris@498 490 if (!feature.values.empty()) {
Chris@498 491 stream << ";\n";
Chris@498 492 //!!! named bins?
Chris@498 493 stream << " af:feature \"" << feature.values[0];
Chris@498 494 for (int j = 1; j < feature.values.size(); ++j) {
Chris@498 495 stream << " " << feature.values[j];
Chris@498 496 }
Chris@498 497 stream << "\" ";
Chris@498 498 }
Chris@498 499
Chris@498 500 stream << ".\n";
Chris@498 501 }
Chris@498 502 }
Chris@498 503
Chris@498 504 void
Chris@507 505 RDFFeatureWriter::writeTrackLevelRDF(QTextStream *sptr,
Chris@507 506 const Transform &transform,
Chris@507 507 const Plugin::OutputDescriptor& od,
Chris@507 508 const Plugin::FeatureList& featureList,
Chris@507 509 PluginRDFDescription &desc,
Chris@507 510 QString signalURI)
Chris@507 511 {
Chris@507 512 if (featureList.empty()) return;
Chris@507 513 QTextStream &stream = *sptr;
Chris@507 514
Chris@507 515 bool plain = (m_plain || !desc.haveDescription());
Chris@507 516
Chris@507 517 QString outputId = od.identifier.c_str();
Chris@507 518 QString featureUri = desc.getOutputFeatureAttributeURI(outputId);
Chris@507 519
Chris@507 520 if (featureUri == "") {
Chris@507 521 cerr << "RDFFeatureWriter::writeTrackLevelRDF: ERROR: No feature URI available -- this function should not have been called!" << endl;
Chris@507 522 return;
Chris@507 523 }
Chris@507 524
Chris@507 525 for (int i = 0; i < featureList.size(); ++i) {
Chris@507 526
Chris@507 527 const Plugin::Feature &feature = featureList[i];
Chris@507 528
Chris@507 529 if (feature.values.empty()) {
Chris@507 530
Chris@507 531 if (feature.label == "") continue;
Chris@507 532
Chris@508 533 stream << signalURI << " " << featureUri << " \"\"\""
Chris@508 534 << feature.label.c_str() << "\"\"\" .\n";
Chris@507 535
Chris@507 536 } else {
Chris@507 537
Chris@507 538 stream << signalURI << " " << featureUri << " \""
Chris@507 539 << feature.values[0] << "\"^^xsd:float .\n";
Chris@507 540 }
Chris@507 541 }
Chris@507 542 }
Chris@507 543
Chris@507 544 void
Chris@498 545 RDFFeatureWriter::writeDenseRDF(QTextStream *sptr,
Chris@498 546 const Transform &transform,
Chris@498 547 const Plugin::OutputDescriptor& od,
Chris@498 548 const Plugin::FeatureList& featureList,
Chris@498 549 PluginRDFDescription &desc,
Chris@498 550 QString signalURI,
Chris@498 551 QString timelineURI)
Chris@498 552 {
Chris@498 553 if (featureList.empty()) return;
Chris@498 554
Chris@498 555 StringTransformPair sp(signalURI, transform);
Chris@498 556
Chris@498 557 if (m_openDenseFeatures.find(sp) == m_openDenseFeatures.end()) {
Chris@498 558
Chris@498 559 StreamBuffer b(sptr, "");
Chris@498 560 m_openDenseFeatures[sp] = b;
Chris@498 561
Chris@498 562 QString &str(m_openDenseFeatures[sp].second);
Chris@498 563 QTextStream stream(&str);
Chris@498 564
Chris@498 565 bool plain = (m_plain || !desc.haveDescription());
Chris@498 566 QString outputId = od.identifier.c_str();
Chris@498 567
Chris@498 568 uint64_t featureNumber = m_count++;
Chris@498 569
Chris@498 570 // need to write out feature timeline map -- for this we need
Chris@498 571 // the sample rate, window length and hop size from the
Chris@498 572 // transform
Chris@498 573
Chris@498 574 stream << "\n:feature_timeline_" << featureNumber << " a tl:DiscreteTimeLine .\n\n";
Chris@498 575
Chris@498 576 size_t stepSize = transform.getStepSize();
Chris@498 577 if (stepSize == 0) {
Chris@498 578 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the step size properly!" << endl;
Chris@498 579 return;
Chris@498 580 }
Chris@498 581
Chris@498 582 size_t blockSize = transform.getBlockSize();
Chris@498 583 if (blockSize == 0) {
Chris@498 584 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the block size properly!" << endl;
Chris@498 585 return;
Chris@498 586 }
Chris@498 587
Chris@498 588 float sampleRate = transform.getSampleRate();
Chris@498 589 if (sampleRate == 0.f) {
Chris@498 590 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the sample rate properly!" << endl;
Chris@498 591 return;
Chris@498 592 }
Chris@498 593
Chris@498 594 stream << ":feature_timeline_map_" << featureNumber
Chris@498 595 << " a tl:UniformSamplingWindowingMap ;\n"
Chris@498 596 << " tl:rangeTimeLine :feature_timeline_" << featureNumber << " ;\n"
Chris@498 597 << " tl:domainTimeLine " << timelineURI << " ;\n"
Chris@498 598 << " tl:sampleRate \"" << int(sampleRate) << "\"^^xsd:int ;\n"
Chris@498 599 << " tl:windowLength \"" << blockSize << "\"^^xsd:int ;\n"
Chris@498 600 << " tl:hopSize \"" << stepSize << "\"^^xsd:int .\n\n";
Chris@498 601
Chris@498 602 stream << signalURI << " af:signal_feature :feature_"
Chris@498 603 << featureNumber << " ." << endl << endl;
Chris@498 604
Chris@498 605 stream << ":feature_" << featureNumber << " a ";
Chris@498 606
Chris@498 607 QString signalTypeURI = desc.getOutputSignalTypeURI(outputId);
Chris@498 608 if (plain || signalTypeURI == "") {
Chris@498 609 if (m_syntheticSignalTypeURIs.find(transform) !=
Chris@498 610 m_syntheticSignalTypeURIs.end()) {
Chris@498 611 stream << m_syntheticSignalTypeURIs[transform] << " ;\n";
Chris@498 612 } else {
Chris@498 613 stream << ":signal_type_" << outputId << " ;\n";
Chris@498 614 }
Chris@498 615 } else {
Chris@498 616 stream << signalTypeURI << " ;\n";
Chris@498 617 }
Chris@498 618
Chris@498 619 stream << " mo:time ["
Chris@498 620 << "\n a tl:Interval ;"
Chris@498 621 << "\n tl:onTimeLine :feature_timeline_" << featureNumber << " ;";
Chris@498 622
Chris@498 623 RealTime startrt = transform.getStartTime();
Chris@498 624 RealTime durationrt = transform.getDuration();
Chris@498 625
Chris@498 626 int start = RealTime::realTime2Frame(startrt, sampleRate) / stepSize;
Chris@498 627 int duration = RealTime::realTime2Frame(durationrt, sampleRate) / stepSize;
Chris@498 628
Chris@498 629 if (start != 0) {
Chris@498 630 stream << "\n tl:start \"" << start << "\"^^xsd:int ;";
Chris@498 631 }
Chris@498 632 if (duration != 0) {
Chris@498 633 stream << "\n tl:duration \"" << duration << "\"^^xsd:int ;";
Chris@498 634 }
Chris@498 635
Chris@498 636 stream << "\n ] ;\n";
Chris@498 637
Chris@498 638 if (od.hasFixedBinCount) {
Chris@498 639 // We only know the height, so write the width as zero
Chris@498 640 stream << " af:dimensions \"" << od.binCount << " 0\" ;\n";
Chris@498 641 }
Chris@498 642
Chris@498 643 stream << " af:value \"";
Chris@498 644 }
Chris@498 645
Chris@498 646 QString &str = m_openDenseFeatures[sp].second;
Chris@498 647 QTextStream stream(&str);
Chris@498 648
Chris@498 649 for (int i = 0; i < featureList.size(); ++i) {
Chris@498 650
Chris@498 651 const Plugin::Feature &feature = featureList[i];
Chris@498 652
Chris@498 653 for (int j = 0; j < feature.values.size(); ++j) {
Chris@498 654 stream << feature.values[j] << " ";
Chris@498 655 }
Chris@498 656 }
Chris@498 657 }
Chris@498 658
Chris@498 659 void RDFFeatureWriter::finish()
Chris@498 660 {
Chris@530 661 cerr << "RDFFeatureWriter::finish()" << endl;
Chris@498 662
Chris@498 663 // close any open dense feature literals
Chris@498 664
Chris@498 665 for (map<StringTransformPair, StreamBuffer>::iterator i =
Chris@498 666 m_openDenseFeatures.begin();
Chris@498 667 i != m_openDenseFeatures.end(); ++i) {
Chris@512 668 // cerr << "closing a stream" << endl;
Chris@498 669 StreamBuffer &b = i->second;
Chris@498 670 *(b.first) << b.second << "\" ." << endl;
Chris@498 671 }
Chris@498 672
Chris@498 673 m_openDenseFeatures.clear();
Chris@530 674 m_startedStreamTransforms.clear();
Chris@530 675
Chris@530 676 FileFeatureWriter::finish();
Chris@498 677 }
Chris@498 678
Chris@498 679