annotate transform/FileFeatureWriter.cpp @ 507:0944d13689b2

* Implement proper RDF feature writing for track level features, using the feature attribute URI given in the plugin description RDF (if there is one)
author Chris Cannam
date Fri, 05 Dec 2008 14:19:04 +0000
parents 823e8a4feff5
children e7a39c45a7a4
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@507 174
Chris@507 175 cerr << "trackId = " << trackId.toStdString() << ", url = " << url.toString().toStdString() << ", infilename = "
Chris@507 176 << infilename.toStdString() << ", basename = " << basename.toStdString() << endl;
Chris@498 177
Chris@498 178
Chris@498 179 if (m_baseDir != "") dirname = QFileInfo(m_baseDir).absoluteFilePath();
Chris@498 180 else if (local) dirname = QFileInfo(infilename).absolutePath();
Chris@498 181 else dirname = QDir::currentPath();
Chris@498 182
Chris@498 183 QString filename;
Chris@498 184
Chris@498 185 if (m_manyFiles && transformId != "") {
Chris@506 186 filename = QString("%1-%2.%3").arg(basename).arg(transformId).arg(m_extension);
Chris@498 187 } else {
Chris@498 188 filename = QString("%1.%2").arg(basename).arg(m_extension);
Chris@498 189 }
Chris@498 190
Chris@498 191 filename = QDir(dirname).filePath(filename);
Chris@498 192
Chris@498 193 if (QFileInfo(filename).exists() && !(m_force || m_append)) {
Chris@498 194 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 195 return "";
Chris@498 196 }
Chris@498 197
Chris@498 198 return filename;
Chris@498 199 }
Chris@498 200
Chris@498 201
Chris@498 202 QFile *FileFeatureWriter::getOutputFile(QString trackId,
Chris@498 203 TransformId transformId)
Chris@498 204 {
Chris@498 205 pair<QString, TransformId> key;
Chris@498 206
Chris@498 207 if (m_singleFileName != "") {
Chris@498 208 key = pair<QString, TransformId>("", "");
Chris@498 209 } else if (m_manyFiles) {
Chris@498 210 key = pair<QString, TransformId>(trackId, transformId);
Chris@498 211 } else {
Chris@498 212 key = pair<QString, TransformId>(trackId, "");
Chris@498 213 }
Chris@498 214
Chris@498 215 if (m_files.find(key) == m_files.end()) {
Chris@498 216
Chris@498 217 QString filename = getOutputFilename(trackId, transformId);
Chris@498 218
Chris@498 219 if (filename == "") { // stdout
Chris@498 220 return 0;
Chris@498 221 }
Chris@498 222
Chris@498 223 cerr << "FileFeatureWriter: NOTE: Using output filename \""
Chris@498 224 << filename.toStdString() << "\"" << endl;
Chris@498 225
Chris@498 226 QFile *file = new QFile(filename);
Chris@498 227 QIODevice::OpenMode mode = (QIODevice::WriteOnly);
Chris@498 228 if (m_append) mode |= QIODevice::Append;
Chris@498 229
Chris@498 230 if (!file->open(mode)) {
Chris@498 231 cerr << "FileFeatureWriter: ERROR: Failed to open output file \"" << filename.toStdString()
Chris@498 232 << "\" for writing" << endl;
Chris@498 233 delete file;
Chris@498 234 m_files[key] = 0;
Chris@498 235 throw FailedToOpenFile(filename);
Chris@498 236 }
Chris@498 237
Chris@498 238 m_files[key] = file;
Chris@498 239 }
Chris@498 240
Chris@498 241 return m_files[key];
Chris@498 242 }
Chris@498 243
Chris@498 244
Chris@498 245 QTextStream *FileFeatureWriter::getOutputStream(QString trackId,
Chris@498 246 TransformId transformId)
Chris@498 247 {
Chris@498 248 QFile *file = getOutputFile(trackId, transformId);
Chris@498 249 if (!file && !m_stdout) {
Chris@498 250 return 0;
Chris@498 251 }
Chris@498 252
Chris@498 253 if (m_streams.find(file) == m_streams.end()) {
Chris@498 254 if (m_stdout) {
Chris@498 255 m_streams[file] = new QTextStream(stdout);
Chris@498 256 } else {
Chris@498 257 m_streams[file] = new QTextStream(file);
Chris@498 258 }
Chris@498 259 }
Chris@498 260
Chris@498 261 return m_streams[file];
Chris@498 262 }
Chris@498 263