annotate 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
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 "FileFeatureWriter.h"
Chris@498 21
Chris@498 22 #include "base/Exceptions.h"
Chris@498 23
Chris@498 24 #include <QTextStream>
Chris@498 25 #include <QFile>
Chris@498 26 #include <QFileInfo>
Chris@498 27 #include <QUrl>
Chris@498 28 #include <QDir>
Chris@498 29
Chris@498 30 using namespace std;
Chris@498 31 using namespace Vamp;
Chris@498 32
Chris@498 33 FileFeatureWriter::FileFeatureWriter(int support,
Chris@498 34 QString extension) :
Chris@498 35 m_support(support),
Chris@498 36 m_extension(extension),
Chris@498 37 m_manyFiles(false),
Chris@498 38 m_stdout(false),
Chris@498 39 m_append(false),
Chris@498 40 m_force(false)
Chris@498 41 {
Chris@498 42 if (!(m_support & SupportOneFilePerTrack)) {
Chris@498 43 if (m_support & SupportOneFilePerTrackTransform) {
Chris@498 44 m_manyFiles = true;
Chris@498 45 } else if (m_support & SupportOneFileTotal) {
Chris@498 46 m_singleFileName = QString("output.%1").arg(m_extension);
Chris@498 47 } else {
Chris@498 48 cerr << "FileFeatureWriter::FileFeatureWriter: ERROR: Invalid support specification " << support << endl;
Chris@498 49 }
Chris@498 50 }
Chris@498 51 }
Chris@498 52
Chris@498 53 FileFeatureWriter::~FileFeatureWriter()
Chris@498 54 {
Chris@498 55 while (!m_streams.empty()) {
Chris@498 56 m_streams.begin()->second->flush();
Chris@498 57 delete m_streams.begin()->second;
Chris@498 58 m_streams.erase(m_streams.begin());
Chris@498 59 }
Chris@498 60 while (!m_files.empty()) {
Chris@498 61 delete m_files.begin()->second;
Chris@498 62 m_files.erase(m_files.begin());
Chris@498 63 }
Chris@498 64 }
Chris@498 65
Chris@498 66 FileFeatureWriter::ParameterList
Chris@498 67 FileFeatureWriter::getSupportedParameters() const
Chris@498 68 {
Chris@498 69 ParameterList pl;
Chris@498 70 Parameter p;
Chris@498 71
Chris@498 72 p.name = "basedir";
Chris@498 73 p.description = "Base output directory path. (The default is the same directory as the input file.)";
Chris@498 74 p.hasArg = true;
Chris@498 75 pl.push_back(p);
Chris@498 76
Chris@498 77 if (m_support & SupportOneFilePerTrackTransform &&
Chris@498 78 m_support & SupportOneFilePerTrack) {
Chris@498 79 p.name = "many-files";
Chris@498 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.)";
Chris@498 81 p.hasArg = false;
Chris@498 82 pl.push_back(p);
Chris@498 83 }
Chris@498 84
Chris@498 85 if (m_support & SupportOneFileTotal) {
Chris@498 86 if (m_support & ~SupportOneFileTotal) { // not only option
Chris@498 87 p.name = "one-file";
Chris@498 88 p.description = "Write all transform results for all input files into the single named output file.";
Chris@498 89 p.hasArg = true;
Chris@498 90 pl.push_back(p);
Chris@498 91 }
Chris@498 92 p.name = "stdout";
Chris@498 93 p.description = "Write all transform results directly to standard output.";
Chris@498 94 p.hasArg = false;
Chris@498 95 pl.push_back(p);
Chris@498 96 }
Chris@498 97
Chris@498 98 p.name = "force";
Chris@498 99 p.description = "If an output file already exists, overwrite it.";
Chris@498 100 p.hasArg = false;
Chris@498 101 pl.push_back(p);
Chris@498 102
Chris@498 103 p.name = "append";
Chris@498 104 p.description = "If an output file already exists, append data to it.";
Chris@498 105 p.hasArg = false;
Chris@498 106 pl.push_back(p);
Chris@498 107
Chris@498 108 return pl;
Chris@498 109 }
Chris@498 110
Chris@498 111 void
Chris@498 112 FileFeatureWriter::setParameters(map<string, string> &params)
Chris@498 113 {
Chris@498 114 for (map<string, string>::iterator i = params.begin();
Chris@498 115 i != params.end(); ++i) {
Chris@498 116 if (i->first == "basedir") {
Chris@498 117 m_baseDir = i->second.c_str();
Chris@498 118 } else if (i->first == "many-files") {
Chris@498 119 if (m_support & SupportOneFilePerTrackTransform &&
Chris@498 120 m_support & SupportOneFilePerTrack) {
Chris@498 121 if (m_singleFileName != "") {
Chris@498 122 cerr << "FileFeatureWriter::setParameters: WARNING: Both one-file and many-files parameters provided, ignoring many-files" << endl;
Chris@498 123 } else {
Chris@498 124 m_manyFiles = true;
Chris@498 125 }
Chris@498 126 }
Chris@498 127 } else if (i->first == "one-file") {
Chris@498 128 if (m_support & SupportOneFileTotal) {
Chris@498 129 if (m_support & ~SupportOneFileTotal) { // not only option
Chris@498 130 if (m_manyFiles) {
Chris@498 131 cerr << "FileFeatureWriter::setParameters: WARNING: Both many-files and one-file parameters provided, ignoring one-file" << endl;
Chris@498 132 } else {
Chris@498 133 m_singleFileName = i->second.c_str();
Chris@498 134 }
Chris@498 135 }
Chris@498 136 }
Chris@498 137 } else if (i->first == "stdout") {
Chris@498 138 if (m_support & SupportOneFileTotal) {
Chris@498 139 if (m_singleFileName != "") {
Chris@498 140 cerr << "FileFeatureWriter::setParameters: WARNING: Both stdout and one-file provided, ignoring stdout" << endl;
Chris@498 141 } else {
Chris@498 142 m_stdout = true;
Chris@498 143 }
Chris@498 144 }
Chris@498 145 } else if (i->first == "append") {
Chris@498 146 m_append = true;
Chris@498 147 } else if (i->first == "force") {
Chris@498 148 m_force = true;
Chris@498 149 }
Chris@498 150 }
Chris@498 151 }
Chris@498 152
Chris@498 153 QString FileFeatureWriter::getOutputFilename(QString trackId,
Chris@498 154 TransformId transformId)
Chris@498 155 {
Chris@498 156 if (m_singleFileName != "") {
Chris@498 157 if (QFileInfo(m_singleFileName).exists() && !(m_force || m_append)) {
Chris@498 158 cerr << "FileFeatureWriter: ERROR: Specified output file \"" << m_singleFileName.toStdString() << "\" exists and neither force nor append flag is specified -- not overwriting" << endl;
Chris@498 159 return "";
Chris@498 160 }
Chris@498 161 return m_singleFileName;
Chris@498 162 }
Chris@498 163
Chris@498 164 if (m_stdout) return "";
Chris@498 165
Chris@498 166 QUrl url(trackId);
Chris@498 167 QString scheme = url.scheme().toLower();
Chris@498 168 bool local = (scheme == "" || scheme == "file" || scheme.length() == 1);
Chris@498 169
Chris@498 170 QString dirname, basename;
Chris@498 171 QString infilename = url.toLocalFile();
Chris@498 172 if (infilename == "") infilename = url.path();
Chris@498 173 basename = QFileInfo(infilename).baseName();
Chris@498 174 // cerr << "url = " << url.toString().toStdString() << ", infilename = "
Chris@498 175 // << infilename.toStdString() << ", basename = " << basename.toStdString() << endl;
Chris@498 176
Chris@498 177
Chris@498 178 if (m_baseDir != "") dirname = QFileInfo(m_baseDir).absoluteFilePath();
Chris@498 179 else if (local) dirname = QFileInfo(infilename).absolutePath();
Chris@498 180 else dirname = QDir::currentPath();
Chris@498 181
Chris@498 182 QString filename;
Chris@498 183
Chris@498 184 if (m_manyFiles && transformId != "") {
Chris@498 185 filename = QString("%1:%2.%3").arg(basename).arg(transformId).arg(m_extension);
Chris@498 186 } else {
Chris@498 187 filename = QString("%1.%2").arg(basename).arg(m_extension);
Chris@498 188 }
Chris@498 189
Chris@498 190 filename = QDir(dirname).filePath(filename);
Chris@498 191
Chris@498 192 if (QFileInfo(filename).exists() && !(m_force || m_append)) {
Chris@498 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;
Chris@498 194 return "";
Chris@498 195 }
Chris@498 196
Chris@498 197 return filename;
Chris@498 198 }
Chris@498 199
Chris@498 200
Chris@498 201 QFile *FileFeatureWriter::getOutputFile(QString trackId,
Chris@498 202 TransformId transformId)
Chris@498 203 {
Chris@498 204 pair<QString, TransformId> key;
Chris@498 205
Chris@498 206 if (m_singleFileName != "") {
Chris@498 207 key = pair<QString, TransformId>("", "");
Chris@498 208 } else if (m_manyFiles) {
Chris@498 209 key = pair<QString, TransformId>(trackId, transformId);
Chris@498 210 } else {
Chris@498 211 key = pair<QString, TransformId>(trackId, "");
Chris@498 212 }
Chris@498 213
Chris@498 214 if (m_files.find(key) == m_files.end()) {
Chris@498 215
Chris@498 216 QString filename = getOutputFilename(trackId, transformId);
Chris@498 217
Chris@498 218 if (filename == "") { // stdout
Chris@498 219 return 0;
Chris@498 220 }
Chris@498 221
Chris@498 222 cerr << "FileFeatureWriter: NOTE: Using output filename \""
Chris@498 223 << filename.toStdString() << "\"" << endl;
Chris@498 224
Chris@498 225 QFile *file = new QFile(filename);
Chris@498 226 QIODevice::OpenMode mode = (QIODevice::WriteOnly);
Chris@498 227 if (m_append) mode |= QIODevice::Append;
Chris@498 228
Chris@498 229 if (!file->open(mode)) {
Chris@498 230 cerr << "FileFeatureWriter: ERROR: Failed to open output file \"" << filename.toStdString()
Chris@498 231 << "\" for writing" << endl;
Chris@498 232 delete file;
Chris@498 233 m_files[key] = 0;
Chris@498 234 throw FailedToOpenFile(filename);
Chris@498 235 }
Chris@498 236
Chris@498 237 m_files[key] = file;
Chris@498 238 }
Chris@498 239
Chris@498 240 return m_files[key];
Chris@498 241 }
Chris@498 242
Chris@498 243
Chris@498 244 QTextStream *FileFeatureWriter::getOutputStream(QString trackId,
Chris@498 245 TransformId transformId)
Chris@498 246 {
Chris@498 247 QFile *file = getOutputFile(trackId, transformId);
Chris@498 248 if (!file && !m_stdout) {
Chris@498 249 return 0;
Chris@498 250 }
Chris@498 251
Chris@498 252 if (m_streams.find(file) == m_streams.end()) {
Chris@498 253 if (m_stdout) {
Chris@498 254 m_streams[file] = new QTextStream(stdout);
Chris@498 255 } else {
Chris@498 256 m_streams[file] = new QTextStream(file);
Chris@498 257 }
Chris@498 258 }
Chris@498 259
Chris@498 260 return m_streams[file];
Chris@498 261 }
Chris@498 262