annotate transform/CSVFeatureWriter.cpp @ 1000:ec6e69373997

Implement end-times option for CSV writer (not yet tested)
author Chris Cannam
date Tue, 14 Oct 2014 17:30:37 +0100
parents e25dc8d57565
children 51bf067de517
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 Visualiser
Chris@498 5 An audio file viewer and annotation editor.
Chris@498 6
Chris@498 7 Sonic Annotator
Chris@498 8 A utility for batch feature extraction from audio files.
Chris@498 9
Chris@498 10 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
Chris@498 11 Copyright 2007-2008 QMUL.
Chris@498 12
Chris@498 13 This program is free software; you can redistribute it and/or
Chris@498 14 modify it under the terms of the GNU General Public License as
Chris@498 15 published by the Free Software Foundation; either version 2 of the
Chris@498 16 License, or (at your option) any later version. See the file
Chris@498 17 COPYING included with this distribution for more information.
Chris@498 18 */
Chris@498 19
Chris@498 20 #include "CSVFeatureWriter.h"
Chris@498 21
Chris@498 22 #include <iostream>
Chris@498 23
Chris@498 24 #include <QRegExp>
Chris@498 25 #include <QTextStream>
Chris@498 26
Chris@498 27 using namespace std;
Chris@498 28 using namespace Vamp;
Chris@498 29
Chris@498 30 CSVFeatureWriter::CSVFeatureWriter() :
Chris@498 31 FileFeatureWriter(SupportOneFilePerTrackTransform |
Chris@997 32 SupportOneFileTotal |
Chris@997 33 SupportStdOut,
Chris@498 34 "csv"),
Chris@669 35 m_separator(","),
Chris@1000 36 m_sampleTiming(false),
Chris@1000 37 m_endTimes(false)
Chris@498 38 {
Chris@498 39 }
Chris@498 40
Chris@498 41 CSVFeatureWriter::~CSVFeatureWriter()
Chris@498 42 {
Chris@498 43 }
Chris@498 44
Chris@998 45 string
Chris@998 46 CSVFeatureWriter::getDescription() const
Chris@998 47 {
Chris@998 48 return "Write features in comma-separated (CSV) format. If transforms are being written to a single file or to stdout, the first column in the output will contain the input audio filename, or an empty string if the feature hails from the same audio file as its predecessor. If transforms are being written to multiple files, the audio filename column will be omitted. Subsequent columns will contain the feature timestamp, then any or all of duration, values, and label.";
Chris@998 49 }
Chris@998 50
Chris@498 51 CSVFeatureWriter::ParameterList
Chris@498 52 CSVFeatureWriter::getSupportedParameters() const
Chris@498 53 {
Chris@498 54 ParameterList pl = FileFeatureWriter::getSupportedParameters();
Chris@498 55 Parameter p;
Chris@498 56
Chris@498 57 p.name = "separator";
Chris@498 58 p.description = "Column separator for output. Default is \",\" (comma).";
Chris@498 59 p.hasArg = true;
Chris@498 60 pl.push_back(p);
Chris@669 61
Chris@669 62 p.name = "sample-timing";
Chris@669 63 p.description = "Show timings as sample frame counts instead of in seconds.";
Chris@669 64 p.hasArg = false;
Chris@669 65 pl.push_back(p);
Chris@1000 66
Chris@1000 67 p.name = "end-times";
Chris@1000 68 p.description = "Show start and end time instead of start and duration, for features with duration.";
Chris@1000 69 p.hasArg = false;
Chris@1000 70 pl.push_back(p);
Chris@498 71
Chris@498 72 return pl;
Chris@498 73 }
Chris@498 74
Chris@498 75 void
Chris@498 76 CSVFeatureWriter::setParameters(map<string, string> &params)
Chris@498 77 {
Chris@498 78 FileFeatureWriter::setParameters(params);
Chris@498 79
Chris@690 80 SVDEBUG << "CSVFeatureWriter::setParameters" << endl;
Chris@498 81 for (map<string, string>::iterator i = params.begin();
Chris@498 82 i != params.end(); ++i) {
Chris@498 83 cerr << i->first << " -> " << i->second << endl;
Chris@498 84 if (i->first == "separator") {
Chris@498 85 m_separator = i->second.c_str();
Chris@669 86 } else if (i->first == "sample-timing") {
Chris@669 87 m_sampleTiming = true;
Chris@1000 88 } else if (i->first == "end-times") {
Chris@1000 89 m_endTimes = true;
Chris@498 90 }
Chris@498 91 }
Chris@498 92 }
Chris@498 93
Chris@498 94 void
Chris@498 95 CSVFeatureWriter::write(QString trackId,
Chris@498 96 const Transform &transform,
Chris@930 97 const Plugin::OutputDescriptor& ,
Chris@498 98 const Plugin::FeatureList& features,
Chris@498 99 std::string summaryType)
Chris@498 100 {
Chris@498 101 // Select appropriate output file for our track/transform
Chris@498 102 // combination
Chris@498 103
Chris@498 104 QTextStream *sptr = getOutputStream(trackId, transform.getIdentifier());
Chris@604 105 if (!sptr) {
Chris@604 106 throw FailedToOpenOutputStream(trackId, transform.getIdentifier());
Chris@604 107 }
Chris@498 108
Chris@498 109 QTextStream &stream = *sptr;
Chris@498 110
Chris@498 111 for (unsigned int i = 0; i < features.size(); ++i) {
Chris@498 112
Chris@514 113 if (m_stdout || m_singleFileName != "") {
Chris@514 114 if (trackId != m_prevPrintedTrackId) {
Chris@514 115 stream << "\"" << trackId << "\"" << m_separator;
Chris@514 116 m_prevPrintedTrackId = trackId;
Chris@514 117 } else {
Chris@514 118 stream << m_separator;
Chris@514 119 }
Chris@514 120 }
Chris@514 121
Chris@669 122 if (m_sampleTiming) {
Chris@498 123
Chris@669 124 stream << Vamp::RealTime::realTime2Frame
Chris@669 125 (features[i].timestamp, transform.getSampleRate());
Chris@669 126
Chris@669 127 if (features[i].hasDuration) {
Chris@669 128 stream << m_separator;
Chris@1000 129 if (m_endTimes) {
Chris@1000 130 stream << Vamp::RealTime::realTime2Frame
Chris@1000 131 (features[i].timestamp + features[i].duration,
Chris@1000 132 transform.getSampleRate());
Chris@1000 133 } else {
Chris@1000 134 stream << Vamp::RealTime::realTime2Frame
Chris@1000 135 (features[i].duration, transform.getSampleRate());
Chris@1000 136 }
Chris@669 137 }
Chris@669 138
Chris@669 139 } else {
Chris@669 140
Chris@669 141 QString timestamp = features[i].timestamp.toString().c_str();
Chris@669 142 timestamp.replace(QRegExp("^ +"), "");
Chris@669 143 stream << timestamp;
Chris@669 144
Chris@669 145 if (features[i].hasDuration) {
Chris@1000 146 if (m_endTimes) {
Chris@1000 147 QString endtime =
Chris@1000 148 (features[i].timestamp + features[i].duration)
Chris@1000 149 .toString().c_str();
Chris@1000 150 endtime.replace(QRegExp("^ +"), "");
Chris@1000 151 stream << m_separator << endtime;
Chris@1000 152 } else {
Chris@1000 153 QString duration = features[i].duration.toString().c_str();
Chris@1000 154 duration.replace(QRegExp("^ +"), "");
Chris@1000 155 stream << m_separator << duration;
Chris@1000 156 }
Chris@669 157 }
Chris@669 158 }
Chris@498 159
Chris@498 160 if (summaryType != "") {
Chris@498 161 stream << m_separator << summaryType.c_str();
Chris@498 162 }
Chris@498 163
Chris@498 164 for (unsigned int j = 0; j < features[i].values.size(); ++j) {
Chris@498 165 stream << m_separator << features[i].values[j];
Chris@498 166 }
Chris@498 167
Chris@514 168 if (features[i].label != "") {
Chris@514 169 stream << m_separator << "\"" << features[i].label.c_str() << "\"";
Chris@514 170 }
Chris@514 171
Chris@498 172 stream << "\n";
Chris@498 173 }
Chris@498 174 }
Chris@498 175
Chris@498 176