comparison transform/FileFeatureWriter.cpp @ 498:fdf5930b7ccc

* Bring FeatureWriter and RDFFeatureWriter into the fold (from Runner) so that we can use them to export features from SV as well
author Chris Cannam
date Fri, 28 Nov 2008 13:47:11 +0000
parents
children 823e8a4feff5
comparison
equal deleted inserted replaced
497:b6dc6c7f402c 498:fdf5930b7ccc
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6
7 Sonic Annotator
8 A utility for batch feature extraction from audio files.
9
10 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
11 Copyright 2007-2008 QMUL.
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version. See the file
17 COPYING included with this distribution for more information.
18 */
19
20 #include "FileFeatureWriter.h"
21
22 #include "base/Exceptions.h"
23
24 #include <QTextStream>
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QUrl>
28 #include <QDir>
29
30 using namespace std;
31 using namespace Vamp;
32
33 FileFeatureWriter::FileFeatureWriter(int support,
34 QString extension) :
35 m_support(support),
36 m_extension(extension),
37 m_manyFiles(false),
38 m_stdout(false),
39 m_append(false),
40 m_force(false)
41 {
42 if (!(m_support & SupportOneFilePerTrack)) {
43 if (m_support & SupportOneFilePerTrackTransform) {
44 m_manyFiles = true;
45 } else if (m_support & SupportOneFileTotal) {
46 m_singleFileName = QString("output.%1").arg(m_extension);
47 } else {
48 cerr << "FileFeatureWriter::FileFeatureWriter: ERROR: Invalid support specification " << support << endl;
49 }
50 }
51 }
52
53 FileFeatureWriter::~FileFeatureWriter()
54 {
55 while (!m_streams.empty()) {
56 m_streams.begin()->second->flush();
57 delete m_streams.begin()->second;
58 m_streams.erase(m_streams.begin());
59 }
60 while (!m_files.empty()) {
61 delete m_files.begin()->second;
62 m_files.erase(m_files.begin());
63 }
64 }
65
66 FileFeatureWriter::ParameterList
67 FileFeatureWriter::getSupportedParameters() const
68 {
69 ParameterList pl;
70 Parameter p;
71
72 p.name = "basedir";
73 p.description = "Base output directory path. (The default is the same directory as the input file.)";
74 p.hasArg = true;
75 pl.push_back(p);
76
77 if (m_support & SupportOneFilePerTrackTransform &&
78 m_support & SupportOneFilePerTrack) {
79 p.name = "many-files";
80 p.description = "Create a separate output file for every combination of input file and transform. The output file names will be based on the input file names. (The default is to create one output file per input audio file, and write all transform results for that input into it.)";
81 p.hasArg = false;
82 pl.push_back(p);
83 }
84
85 if (m_support & SupportOneFileTotal) {
86 if (m_support & ~SupportOneFileTotal) { // not only option
87 p.name = "one-file";
88 p.description = "Write all transform results for all input files into the single named output file.";
89 p.hasArg = true;
90 pl.push_back(p);
91 }
92 p.name = "stdout";
93 p.description = "Write all transform results directly to standard output.";
94 p.hasArg = false;
95 pl.push_back(p);
96 }
97
98 p.name = "force";
99 p.description = "If an output file already exists, overwrite it.";
100 p.hasArg = false;
101 pl.push_back(p);
102
103 p.name = "append";
104 p.description = "If an output file already exists, append data to it.";
105 p.hasArg = false;
106 pl.push_back(p);
107
108 return pl;
109 }
110
111 void
112 FileFeatureWriter::setParameters(map<string, string> &params)
113 {
114 for (map<string, string>::iterator i = params.begin();
115 i != params.end(); ++i) {
116 if (i->first == "basedir") {
117 m_baseDir = i->second.c_str();
118 } else if (i->first == "many-files") {
119 if (m_support & SupportOneFilePerTrackTransform &&
120 m_support & SupportOneFilePerTrack) {
121 if (m_singleFileName != "") {
122 cerr << "FileFeatureWriter::setParameters: WARNING: Both one-file and many-files parameters provided, ignoring many-files" << endl;
123 } else {
124 m_manyFiles = true;
125 }
126 }
127 } else if (i->first == "one-file") {
128 if (m_support & SupportOneFileTotal) {
129 if (m_support & ~SupportOneFileTotal) { // not only option
130 if (m_manyFiles) {
131 cerr << "FileFeatureWriter::setParameters: WARNING: Both many-files and one-file parameters provided, ignoring one-file" << endl;
132 } else {
133 m_singleFileName = i->second.c_str();
134 }
135 }
136 }
137 } else if (i->first == "stdout") {
138 if (m_support & SupportOneFileTotal) {
139 if (m_singleFileName != "") {
140 cerr << "FileFeatureWriter::setParameters: WARNING: Both stdout and one-file provided, ignoring stdout" << endl;
141 } else {
142 m_stdout = true;
143 }
144 }
145 } else if (i->first == "append") {
146 m_append = true;
147 } else if (i->first == "force") {
148 m_force = true;
149 }
150 }
151 }
152
153 QString FileFeatureWriter::getOutputFilename(QString trackId,
154 TransformId transformId)
155 {
156 if (m_singleFileName != "") {
157 if (QFileInfo(m_singleFileName).exists() && !(m_force || m_append)) {
158 cerr << "FileFeatureWriter: ERROR: Specified output file \"" << m_singleFileName.toStdString() << "\" exists and neither force nor append flag is specified -- not overwriting" << endl;
159 return "";
160 }
161 return m_singleFileName;
162 }
163
164 if (m_stdout) return "";
165
166 QUrl url(trackId);
167 QString scheme = url.scheme().toLower();
168 bool local = (scheme == "" || scheme == "file" || scheme.length() == 1);
169
170 QString dirname, basename;
171 QString infilename = url.toLocalFile();
172 if (infilename == "") infilename = url.path();
173 basename = QFileInfo(infilename).baseName();
174 // cerr << "url = " << url.toString().toStdString() << ", infilename = "
175 // << infilename.toStdString() << ", basename = " << basename.toStdString() << endl;
176
177
178 if (m_baseDir != "") dirname = QFileInfo(m_baseDir).absoluteFilePath();
179 else if (local) dirname = QFileInfo(infilename).absolutePath();
180 else dirname = QDir::currentPath();
181
182 QString filename;
183
184 if (m_manyFiles && transformId != "") {
185 filename = QString("%1:%2.%3").arg(basename).arg(transformId).arg(m_extension);
186 } else {
187 filename = QString("%1.%2").arg(basename).arg(m_extension);
188 }
189
190 filename = QDir(dirname).filePath(filename);
191
192 if (QFileInfo(filename).exists() && !(m_force || m_append)) {
193 cerr << "FileFeatureWriter: ERROR: Output file \"" << filename.toStdString() << "\" exists (for input file or URL \"" << trackId.toStdString() << "\" and transform \"" << transformId.toStdString() << "\") and neither force nor append is specified -- not overwriting" << endl;
194 return "";
195 }
196
197 return filename;
198 }
199
200
201 QFile *FileFeatureWriter::getOutputFile(QString trackId,
202 TransformId transformId)
203 {
204 pair<QString, TransformId> key;
205
206 if (m_singleFileName != "") {
207 key = pair<QString, TransformId>("", "");
208 } else if (m_manyFiles) {
209 key = pair<QString, TransformId>(trackId, transformId);
210 } else {
211 key = pair<QString, TransformId>(trackId, "");
212 }
213
214 if (m_files.find(key) == m_files.end()) {
215
216 QString filename = getOutputFilename(trackId, transformId);
217
218 if (filename == "") { // stdout
219 return 0;
220 }
221
222 cerr << "FileFeatureWriter: NOTE: Using output filename \""
223 << filename.toStdString() << "\"" << endl;
224
225 QFile *file = new QFile(filename);
226 QIODevice::OpenMode mode = (QIODevice::WriteOnly);
227 if (m_append) mode |= QIODevice::Append;
228
229 if (!file->open(mode)) {
230 cerr << "FileFeatureWriter: ERROR: Failed to open output file \"" << filename.toStdString()
231 << "\" for writing" << endl;
232 delete file;
233 m_files[key] = 0;
234 throw FailedToOpenFile(filename);
235 }
236
237 m_files[key] = file;
238 }
239
240 return m_files[key];
241 }
242
243
244 QTextStream *FileFeatureWriter::getOutputStream(QString trackId,
245 TransformId transformId)
246 {
247 QFile *file = getOutputFile(trackId, transformId);
248 if (!file && !m_stdout) {
249 return 0;
250 }
251
252 if (m_streams.find(file) == m_streams.end()) {
253 if (m_stdout) {
254 m_streams[file] = new QTextStream(stdout);
255 } else {
256 m_streams[file] = new QTextStream(file);
257 }
258 }
259
260 return m_streams[file];
261 }
262