annotate rdf/RDFFeatureWriter.cpp @ 503:3176aade1a03

* Make RDFTransformFactory::writeTransformToRDF write out partial library and plugin descriptions adequate to identify the plugin on disk, if no RDF description for the plugin has been found
author Chris Cannam
date Fri, 05 Dec 2008 09:40:42 +0000
parents 83eae5239db6
children 3376dc26dece
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@498 26 #include <QRegExp>
Chris@498 27
Chris@498 28 using namespace std;
Chris@498 29 using Vamp::Plugin;
Chris@498 30 using Vamp::PluginBase;
Chris@498 31
Chris@498 32 RDFFeatureWriter::RDFFeatureWriter() :
Chris@498 33 FileFeatureWriter(SupportOneFilePerTrackTransform |
Chris@498 34 SupportOneFilePerTrack |
Chris@498 35 SupportOneFileTotal,
Chris@498 36 "n3"),
Chris@498 37 m_plain(false),
Chris@498 38 m_count(0)
Chris@498 39 {
Chris@498 40 }
Chris@498 41
Chris@498 42 RDFFeatureWriter::~RDFFeatureWriter()
Chris@498 43 {
Chris@498 44 }
Chris@498 45
Chris@498 46 RDFFeatureWriter::ParameterList
Chris@498 47 RDFFeatureWriter::getSupportedParameters() const
Chris@498 48 {
Chris@498 49 ParameterList pl = FileFeatureWriter::getSupportedParameters();
Chris@498 50 Parameter p;
Chris@498 51
Chris@498 52 p.name = "plain";
Chris@498 53 p.description = "Use \"plain\" RDF even if transform metadata is available.";
Chris@498 54 p.hasArg = false;
Chris@498 55 pl.push_back(p);
Chris@498 56
Chris@498 57 p.name = "signal-uri";
Chris@498 58 p.description = "Link the output RDF to the given signal URI.";
Chris@498 59 p.hasArg = true;
Chris@498 60 pl.push_back(p);
Chris@498 61
Chris@498 62 return pl;
Chris@498 63 }
Chris@498 64
Chris@498 65 void
Chris@498 66 RDFFeatureWriter::setParameters(map<string, string> &params)
Chris@498 67 {
Chris@498 68 FileFeatureWriter::setParameters(params);
Chris@498 69
Chris@498 70 for (map<string, string>::iterator i = params.begin();
Chris@498 71 i != params.end(); ++i) {
Chris@498 72 if (i->first == "plain") {
Chris@498 73 m_plain = true;
Chris@498 74 }
Chris@498 75 if (i->first == "signal-uri") {
Chris@498 76 m_suri = i->second.c_str();
Chris@498 77 }
Chris@498 78 }
Chris@498 79 }
Chris@498 80
Chris@498 81 void RDFFeatureWriter::write(QString trackId,
Chris@498 82 const Transform &transform,
Chris@498 83 const Plugin::OutputDescriptor& output,
Chris@498 84 const Plugin::FeatureList& features,
Chris@498 85 std::string summaryType)
Chris@498 86 {
Chris@498 87 QString pluginId = transform.getPluginIdentifier();
Chris@498 88
Chris@498 89 if (m_rdfDescriptions.find(pluginId) == m_rdfDescriptions.end()) {
Chris@498 90
Chris@498 91 m_rdfDescriptions[pluginId] = PluginRDFDescription(pluginId);
Chris@498 92
Chris@498 93 if (m_rdfDescriptions[pluginId].haveDescription()) {
Chris@498 94 cerr << "NOTE: Have RDF description for plugin ID \""
Chris@498 95 << pluginId.toStdString() << "\"" << endl;
Chris@498 96 } else {
Chris@498 97 cerr << "NOTE: Do not have RDF description for plugin ID \""
Chris@498 98 << pluginId.toStdString() << "\"" << endl;
Chris@498 99 }
Chris@498 100 }
Chris@498 101
Chris@498 102 // Need to select appropriate output file for our track/transform
Chris@498 103 // combination
Chris@498 104
Chris@498 105 QTextStream *stream = getOutputStream(trackId, transform.getIdentifier());
Chris@498 106 if (!stream) return; //!!! this is probably better handled with an exception
Chris@498 107
Chris@498 108 if (m_startedStreamTransforms.find(stream) ==
Chris@498 109 m_startedStreamTransforms.end()) {
Chris@498 110 cerr << "This stream is new, writing prefixes" << endl;
Chris@498 111 writePrefixes(stream);
Chris@498 112 if (m_singleFileName == "" && !m_stdout) {
Chris@498 113 writeSignalDescription(stream, trackId);
Chris@498 114 }
Chris@498 115 }
Chris@498 116
Chris@498 117 if (m_startedStreamTransforms[stream].find(transform) ==
Chris@498 118 m_startedStreamTransforms[stream].end()) {
Chris@498 119 m_startedStreamTransforms[stream].insert(transform);
Chris@498 120 writeLocalFeatureTypes
Chris@498 121 (stream, transform, output, m_rdfDescriptions[pluginId]);
Chris@498 122 }
Chris@498 123
Chris@498 124 if (m_singleFileName != "" || m_stdout) {
Chris@498 125 if (m_startedTrackIds.find(trackId) == m_startedTrackIds.end()) {
Chris@498 126 writeSignalDescription(stream, trackId);
Chris@498 127 m_startedTrackIds.insert(trackId);
Chris@498 128 }
Chris@498 129 }
Chris@498 130
Chris@498 131 QString timelineURI = m_trackTimelineURIs[trackId];
Chris@498 132
Chris@498 133 if (timelineURI == "") {
Chris@498 134 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing features without having established a timeline URI!" << endl;
Chris@498 135 exit(1);
Chris@498 136 }
Chris@498 137
Chris@498 138 if (summaryType != "") {
Chris@498 139
Chris@498 140 writeSparseRDF(stream, transform, output, features,
Chris@498 141 m_rdfDescriptions[pluginId], timelineURI);
Chris@498 142
Chris@498 143 } else if (m_rdfDescriptions[pluginId].haveDescription() &&
Chris@498 144 m_rdfDescriptions[pluginId].getOutputDisposition
Chris@498 145 (output.identifier.c_str()) ==
Chris@498 146 PluginRDFDescription::OutputDense) {
Chris@498 147
Chris@498 148 QString signalURI = m_trackSignalURIs[trackId];
Chris@498 149
Chris@498 150 if (signalURI == "") {
Chris@498 151 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having established a signal URI!" << endl;
Chris@498 152 exit(1);
Chris@498 153 }
Chris@498 154
Chris@498 155 writeDenseRDF(stream, transform, output, features,
Chris@498 156 m_rdfDescriptions[pluginId], signalURI, timelineURI);
Chris@498 157
Chris@498 158 } else {
Chris@498 159
Chris@498 160 writeSparseRDF(stream, transform, output, features,
Chris@498 161 m_rdfDescriptions[pluginId], timelineURI);
Chris@498 162 }
Chris@498 163 }
Chris@498 164
Chris@498 165 void
Chris@498 166 RDFFeatureWriter::writePrefixes(QTextStream *sptr)
Chris@498 167 {
Chris@498 168 QTextStream &stream = *sptr;
Chris@498 169
Chris@498 170 stream << "@prefix dc: <http://purl.org/dc/elements/1.1/> .\n"
Chris@498 171 << "@prefix mo: <http://purl.org/ontology/mo/> .\n"
Chris@498 172 << "@prefix af: <http://purl.org/ontology/af/> .\n"
Chris@498 173 << "@prefix event: <http://purl.org/NET/c4dm/event.owl#> .\n"
Chris@498 174 << "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
Chris@498 175 << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
Chris@498 176 << "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n"
Chris@498 177 << "@prefix tl: <http://purl.org/NET/c4dm/timeline.owl#> .\n"
Chris@498 178 << "@prefix vamp: <http://purl.org/ontology/vamp/> .\n"
Chris@498 179 << "@prefix : <#> .\n\n";
Chris@498 180 }
Chris@498 181
Chris@498 182 void
Chris@498 183 RDFFeatureWriter::writeSignalDescription(QTextStream *sptr,
Chris@498 184 QString trackId)
Chris@498 185 {
Chris@498 186 QTextStream &stream = *sptr;
Chris@498 187
Chris@498 188 /*
Chris@498 189 * Describe signal we're analysing (AudioFile, Signal, TimeLine, etc.)
Chris@498 190 */
Chris@498 191
Chris@498 192 QUrl url(trackId);
Chris@498 193 QString scheme = url.scheme().toLower();
Chris@498 194 bool local = (scheme == "" || scheme == "file" || scheme.length() == 1);
Chris@498 195
Chris@498 196 if (local) {
Chris@498 197 if (scheme == "") {
Chris@498 198 url.setScheme("file");
Chris@498 199 } else if (scheme.length() == 1) { // DOS drive letter!
Chris@498 200 url.setScheme("file");
Chris@498 201 url.setPath(scheme + ":" + url.path());
Chris@498 202 }
Chris@498 203 }
Chris@498 204
Chris@498 205 //!!! FIX: If we are appending, we need to start counting after
Chris@498 206 //all of the existing counts that are already in the file!
Chris@498 207
Chris@498 208 uint64_t signalCount = m_count++;
Chris@498 209
Chris@498 210 if (m_trackSignalURIs.find(trackId) == m_trackSignalURIs.end()) {
Chris@498 211 m_trackSignalURIs[trackId] = QString(":signal_%1").arg(signalCount);
Chris@498 212 }
Chris@498 213
Chris@498 214 if (m_suri != NULL) {
Chris@498 215 m_trackSignalURIs[trackId] = "<" + m_suri + ">";
Chris@498 216 }
Chris@498 217 QString signalURI = m_trackSignalURIs[trackId];
Chris@498 218
Chris@498 219 if (m_trackTimelineURIs.find(trackId) == m_trackTimelineURIs.end()) {
Chris@498 220 m_trackTimelineURIs[trackId] = QString(":signal_timeline_%1").arg(signalCount);
Chris@498 221 }
Chris@498 222 QString timelineURI = m_trackTimelineURIs[trackId];
Chris@498 223
Chris@500 224 if (trackId != "") {
Chris@500 225 stream << "\n<" << url.toEncoded().data() << "> a mo:AudioFile .\n\n";
Chris@500 226 }
Chris@500 227
Chris@500 228 stream << signalURI << " a mo:Signal ;\n";
Chris@500 229
Chris@500 230 if (trackId != "") {
Chris@500 231 stream << " mo:available_as <" << url.toEncoded().data()
Chris@500 232 << "> ;\n";
Chris@500 233 }
Chris@500 234
Chris@500 235 stream << " mo:time [\n"
Chris@498 236 << " a tl:Interval ;\n"
Chris@498 237 << " tl:onTimeLine "
Chris@498 238 << timelineURI << "\n ] .\n\n";
Chris@498 239 }
Chris@498 240
Chris@498 241 void
Chris@498 242 RDFFeatureWriter::writeLocalFeatureTypes(QTextStream *sptr,
Chris@498 243 const Transform &transform,
Chris@498 244 const Plugin::OutputDescriptor &od,
Chris@498 245 PluginRDFDescription &desc)
Chris@498 246 {
Chris@498 247 QString outputId = od.identifier.c_str();
Chris@498 248 QTextStream &stream = *sptr;
Chris@498 249
Chris@498 250 bool needEventType = false;
Chris@498 251 bool needSignalType = false;
Chris@498 252
Chris@498 253 //!!! feature attribute type is not yet supported
Chris@498 254
Chris@498 255 //!!! bin names, extents and so on can be written out using e.g. vamp:bin_names ( "a" "b" "c" )
Chris@498 256
Chris@498 257 if (desc.getOutputDisposition(outputId) ==
Chris@498 258 PluginRDFDescription::OutputDense) {
Chris@498 259
Chris@498 260 // no feature events, so may need signal type but won't need
Chris@498 261 // event type
Chris@498 262
Chris@498 263 if (m_plain) {
Chris@498 264
Chris@498 265 needSignalType = true;
Chris@498 266
Chris@498 267 } else if (desc.getOutputSignalTypeURI(outputId) == "") {
Chris@498 268
Chris@498 269 needSignalType = true;
Chris@498 270 }
Chris@498 271
Chris@498 272 } else {
Chris@498 273
Chris@498 274 // may need event type but won't need signal type
Chris@498 275
Chris@498 276 if (m_plain) {
Chris@498 277
Chris@498 278 needEventType = true;
Chris@498 279
Chris@498 280 } else if (desc.getOutputEventTypeURI(outputId) == "") {
Chris@498 281
Chris@498 282 needEventType = true;
Chris@498 283 }
Chris@498 284 }
Chris@498 285
Chris@498 286 QString transformUri;
Chris@498 287 if (m_transformURIs.find(transform) != m_transformURIs.end()) {
Chris@498 288 transformUri = m_transformURIs[transform];
Chris@498 289 } else {
Chris@498 290 transformUri = QString(":transform_%1_%2").arg(m_count++).arg(outputId);
Chris@498 291 m_transformURIs[transform] = transformUri;
Chris@498 292 }
Chris@498 293
Chris@500 294 if (transform.getIdentifier() != "") {
Chris@500 295 stream << RDFTransformFactory::writeTransformToRDF(transform, transformUri)
Chris@500 296 << endl;
Chris@500 297 }
Chris@498 298
Chris@498 299 if (needEventType) {
Chris@498 300
Chris@498 301 QString uri;
Chris@498 302 if (m_syntheticEventTypeURIs.find(transform) !=
Chris@498 303 m_syntheticEventTypeURIs.end()) {
Chris@498 304 uri = m_syntheticEventTypeURIs[transform];
Chris@498 305 } else {
Chris@498 306 uri = QString(":event_type_%1").arg(m_count++);
Chris@498 307 m_syntheticEventTypeURIs[transform] = uri;
Chris@498 308 }
Chris@498 309
Chris@498 310 stream << uri
Chris@498 311 << " rdfs:subClassOf event:Event ;" << endl
Chris@498 312 << " dc:title \"" << od.name.c_str() << "\" ;" << endl
Chris@498 313 << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
Chris@498 314 << " dc:description \"" << od.description.c_str() << "\" ."
Chris@498 315 << endl << endl;
Chris@498 316 }
Chris@498 317
Chris@498 318 if (needSignalType) {
Chris@498 319
Chris@498 320 QString uri;
Chris@498 321 if (m_syntheticSignalTypeURIs.find(transform) !=
Chris@498 322 m_syntheticSignalTypeURIs.end()) {
Chris@498 323 uri = m_syntheticSignalTypeURIs[transform];
Chris@498 324 } else {
Chris@498 325 uri = QString(":signal_type_%1").arg(m_count++);
Chris@498 326 m_syntheticSignalTypeURIs[transform] = uri;
Chris@498 327 }
Chris@498 328
Chris@498 329 stream << uri
Chris@498 330 << " rdfs:subClassOf af:Signal ;" << endl
Chris@498 331 << " dc:title \"" << od.name.c_str() << "\" ;" << endl
Chris@498 332 << " dc:format \"" << od.unit.c_str() << "\" ;" << endl
Chris@498 333 << " dc:description \"" << od.description.c_str() << "\" ."
Chris@498 334 << endl << endl;
Chris@498 335 }
Chris@498 336 }
Chris@498 337
Chris@498 338 void
Chris@498 339 RDFFeatureWriter::writeSparseRDF(QTextStream *sptr,
Chris@498 340 const Transform &transform,
Chris@498 341 const Plugin::OutputDescriptor& od,
Chris@498 342 const Plugin::FeatureList& featureList,
Chris@498 343 PluginRDFDescription &desc,
Chris@498 344 QString timelineURI)
Chris@498 345 {
Chris@498 346 if (featureList.empty()) return;
Chris@498 347 QTextStream &stream = *sptr;
Chris@498 348
Chris@498 349 bool plain = (m_plain || !desc.haveDescription());
Chris@498 350
Chris@498 351 QString outputId = od.identifier.c_str();
Chris@498 352
Chris@498 353 // iterate through FeatureLists
Chris@498 354
Chris@498 355 for (int i = 0; i < featureList.size(); ++i) {
Chris@498 356
Chris@498 357 const Plugin::Feature &feature = featureList[i];
Chris@498 358 uint64_t featureNumber = m_count++;
Chris@498 359
Chris@498 360 stream << ":event_" << featureNumber << " a ";
Chris@498 361
Chris@498 362 QString eventTypeURI = desc.getOutputEventTypeURI(outputId);
Chris@498 363 if (plain || eventTypeURI == "") {
Chris@498 364 if (m_syntheticEventTypeURIs.find(transform) !=
Chris@498 365 m_syntheticEventTypeURIs.end()) {
Chris@498 366 stream << m_syntheticEventTypeURIs[transform] << " ;\n";
Chris@498 367 } else {
Chris@498 368 stream << ":event_type_" << outputId << " ;\n";
Chris@498 369 }
Chris@498 370 } else {
Chris@498 371 stream << "<" << eventTypeURI << "> ;\n";
Chris@498 372 }
Chris@498 373
Chris@498 374 QString timestamp = feature.timestamp.toString().c_str();
Chris@498 375 timestamp.replace(QRegExp("^ +"), "");
Chris@498 376
Chris@498 377 if (feature.hasDuration && feature.duration > Vamp::RealTime::zeroTime) {
Chris@498 378
Chris@498 379 QString duration = feature.duration.toString().c_str();
Chris@498 380 duration.replace(QRegExp("^ +"), "");
Chris@498 381
Chris@498 382 stream << " event:time [ \n"
Chris@498 383 << " a tl:Interval ;\n"
Chris@498 384 << " tl:onTimeLine " << timelineURI << " ;\n"
Chris@498 385 << " tl:beginsAt \"PT" << timestamp
Chris@498 386 << "S\"^^xsd:duration ;\n"
Chris@498 387 << " tl:duration \"PT" << duration
Chris@498 388 << "S\"^^xsd:duration ;\n"
Chris@498 389 << " ] ";
Chris@498 390
Chris@498 391 } else {
Chris@498 392
Chris@498 393 stream << " event:time [ \n"
Chris@498 394 << " a tl:Instant ;\n" //location of the event in time
Chris@498 395 << " tl:onTimeLine " << timelineURI << " ;\n"
Chris@498 396 << " tl:at \"PT" << timestamp
Chris@498 397 << "S\"^^xsd:duration ;\n ] ";
Chris@498 398 }
Chris@498 399
Chris@500 400 if (transform.getIdentifier() != "") {
Chris@500 401 stream << ";\n";
Chris@500 402 stream << " vamp:computed_by " << m_transformURIs[transform] << " ";
Chris@500 403 }
Chris@498 404
Chris@498 405 if (feature.label.length() > 0) {
Chris@498 406 stream << ";\n";
Chris@498 407 stream << " rdfs:label \"" << feature.label.c_str() << "\" ";
Chris@498 408 }
Chris@498 409
Chris@498 410 if (!feature.values.empty()) {
Chris@498 411 stream << ";\n";
Chris@498 412 //!!! named bins?
Chris@498 413 stream << " af:feature \"" << feature.values[0];
Chris@498 414 for (int j = 1; j < feature.values.size(); ++j) {
Chris@498 415 stream << " " << feature.values[j];
Chris@498 416 }
Chris@498 417 stream << "\" ";
Chris@498 418 }
Chris@498 419
Chris@498 420 stream << ".\n";
Chris@498 421 }
Chris@498 422 }
Chris@498 423
Chris@498 424 void
Chris@498 425 RDFFeatureWriter::writeDenseRDF(QTextStream *sptr,
Chris@498 426 const Transform &transform,
Chris@498 427 const Plugin::OutputDescriptor& od,
Chris@498 428 const Plugin::FeatureList& featureList,
Chris@498 429 PluginRDFDescription &desc,
Chris@498 430 QString signalURI,
Chris@498 431 QString timelineURI)
Chris@498 432 {
Chris@498 433 if (featureList.empty()) return;
Chris@498 434
Chris@498 435 StringTransformPair sp(signalURI, transform);
Chris@498 436
Chris@498 437 if (m_openDenseFeatures.find(sp) == m_openDenseFeatures.end()) {
Chris@498 438
Chris@498 439 StreamBuffer b(sptr, "");
Chris@498 440 m_openDenseFeatures[sp] = b;
Chris@498 441
Chris@498 442 QString &str(m_openDenseFeatures[sp].second);
Chris@498 443 QTextStream stream(&str);
Chris@498 444
Chris@498 445 bool plain = (m_plain || !desc.haveDescription());
Chris@498 446 QString outputId = od.identifier.c_str();
Chris@498 447
Chris@498 448 uint64_t featureNumber = m_count++;
Chris@498 449
Chris@498 450 // need to write out feature timeline map -- for this we need
Chris@498 451 // the sample rate, window length and hop size from the
Chris@498 452 // transform
Chris@498 453
Chris@498 454 stream << "\n:feature_timeline_" << featureNumber << " a tl:DiscreteTimeLine .\n\n";
Chris@498 455
Chris@498 456 size_t stepSize = transform.getStepSize();
Chris@498 457 if (stepSize == 0) {
Chris@498 458 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the step size properly!" << endl;
Chris@498 459 return;
Chris@498 460 }
Chris@498 461
Chris@498 462 size_t blockSize = transform.getBlockSize();
Chris@498 463 if (blockSize == 0) {
Chris@498 464 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the block size properly!" << endl;
Chris@498 465 return;
Chris@498 466 }
Chris@498 467
Chris@498 468 float sampleRate = transform.getSampleRate();
Chris@498 469 if (sampleRate == 0.f) {
Chris@498 470 cerr << "RDFFeatureWriter: INTERNAL ERROR: writing dense features without having set the sample rate properly!" << endl;
Chris@498 471 return;
Chris@498 472 }
Chris@498 473
Chris@498 474 stream << ":feature_timeline_map_" << featureNumber
Chris@498 475 << " a tl:UniformSamplingWindowingMap ;\n"
Chris@498 476 << " tl:rangeTimeLine :feature_timeline_" << featureNumber << " ;\n"
Chris@498 477 << " tl:domainTimeLine " << timelineURI << " ;\n"
Chris@498 478 << " tl:sampleRate \"" << int(sampleRate) << "\"^^xsd:int ;\n"
Chris@498 479 << " tl:windowLength \"" << blockSize << "\"^^xsd:int ;\n"
Chris@498 480 << " tl:hopSize \"" << stepSize << "\"^^xsd:int .\n\n";
Chris@498 481
Chris@498 482 stream << signalURI << " af:signal_feature :feature_"
Chris@498 483 << featureNumber << " ." << endl << endl;
Chris@498 484
Chris@498 485 stream << ":feature_" << featureNumber << " a ";
Chris@498 486
Chris@498 487 QString signalTypeURI = desc.getOutputSignalTypeURI(outputId);
Chris@498 488 if (plain || signalTypeURI == "") {
Chris@498 489 if (m_syntheticSignalTypeURIs.find(transform) !=
Chris@498 490 m_syntheticSignalTypeURIs.end()) {
Chris@498 491 stream << m_syntheticSignalTypeURIs[transform] << " ;\n";
Chris@498 492 } else {
Chris@498 493 stream << ":signal_type_" << outputId << " ;\n";
Chris@498 494 }
Chris@498 495 } else {
Chris@498 496 stream << signalTypeURI << " ;\n";
Chris@498 497 }
Chris@498 498
Chris@498 499 stream << " mo:time ["
Chris@498 500 << "\n a tl:Interval ;"
Chris@498 501 << "\n tl:onTimeLine :feature_timeline_" << featureNumber << " ;";
Chris@498 502
Chris@498 503 RealTime startrt = transform.getStartTime();
Chris@498 504 RealTime durationrt = transform.getDuration();
Chris@498 505
Chris@498 506 int start = RealTime::realTime2Frame(startrt, sampleRate) / stepSize;
Chris@498 507 int duration = RealTime::realTime2Frame(durationrt, sampleRate) / stepSize;
Chris@498 508
Chris@498 509 if (start != 0) {
Chris@498 510 stream << "\n tl:start \"" << start << "\"^^xsd:int ;";
Chris@498 511 }
Chris@498 512 if (duration != 0) {
Chris@498 513 stream << "\n tl:duration \"" << duration << "\"^^xsd:int ;";
Chris@498 514 }
Chris@498 515
Chris@498 516 stream << "\n ] ;\n";
Chris@498 517
Chris@498 518 if (od.hasFixedBinCount) {
Chris@498 519 // We only know the height, so write the width as zero
Chris@498 520 stream << " af:dimensions \"" << od.binCount << " 0\" ;\n";
Chris@498 521 }
Chris@498 522
Chris@498 523 stream << " af:value \"";
Chris@498 524 }
Chris@498 525
Chris@498 526 QString &str = m_openDenseFeatures[sp].second;
Chris@498 527 QTextStream stream(&str);
Chris@498 528
Chris@498 529 for (int i = 0; i < featureList.size(); ++i) {
Chris@498 530
Chris@498 531 const Plugin::Feature &feature = featureList[i];
Chris@498 532
Chris@498 533 for (int j = 0; j < feature.values.size(); ++j) {
Chris@498 534 stream << feature.values[j] << " ";
Chris@498 535 }
Chris@498 536 }
Chris@498 537 }
Chris@498 538
Chris@498 539 void RDFFeatureWriter::finish()
Chris@498 540 {
Chris@498 541 // cerr << "RDFFeatureWriter::finish()" << endl;
Chris@498 542
Chris@498 543 // close any open dense feature literals
Chris@498 544
Chris@498 545 for (map<StringTransformPair, StreamBuffer>::iterator i =
Chris@498 546 m_openDenseFeatures.begin();
Chris@498 547 i != m_openDenseFeatures.end(); ++i) {
Chris@498 548 cerr << "closing a stream" << endl;
Chris@498 549 StreamBuffer &b = i->second;
Chris@498 550 *(b.first) << b.second << "\" ." << endl;
Chris@498 551 }
Chris@498 552
Chris@498 553 m_openDenseFeatures.clear();
Chris@498 554 }
Chris@498 555
Chris@498 556