annotate runner/AudioDBFeatureWriter.cpp @ 121:5200446bbc6b test-reorg

Check for multiple transforms. But one of these tests fails, so we'd better go back to development branch and sort out why!
author Chris Cannam
date Wed, 08 Oct 2014 15:38:34 +0100
parents 92911f967a16
children ee56e3e9eeb5
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Annotator
Chris@0 5 A utility for batch feature extraction from audio files.
Chris@0 6 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
Chris@0 7 Copyright 2007-2008 QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include <fstream>
Chris@0 17
Chris@0 18 #include <QFileInfo>
Chris@0 19
Chris@0 20 #include "AudioDBFeatureWriter.h"
Chris@0 21
Chris@0 22 using namespace std;
Chris@0 23 using namespace Vamp;
Chris@0 24
Chris@0 25 string
Chris@0 26 AudioDBFeatureWriter::catalogueIdParam = "catid";
Chris@0 27
Chris@0 28 string
Chris@0 29 AudioDBFeatureWriter::baseDirParam = "basedir";
Chris@0 30
Chris@0 31 struct AudioDBFeatureWriter::TrackStream
Chris@0 32 {
Chris@0 33 QString trackid;
Chris@0 34 ofstream* ofs;
Chris@0 35 };
Chris@0 36
Chris@0 37 AudioDBFeatureWriter::AudioDBFeatureWriter() :
Chris@0 38 catalogueId("catalog"), baseDir("audiodb")
Chris@0 39 {
Chris@0 40
Chris@0 41 }
Chris@0 42
Chris@0 43 AudioDBFeatureWriter::~AudioDBFeatureWriter()
Chris@0 44 {
Chris@0 45 // close all open files
Chris@0 46 for (map<string, TrackStream>::iterator iter = dbfiles.begin(); iter != dbfiles.end(); ++iter)
Chris@0 47 {
Chris@0 48 if (iter->second.ofs) {
Chris@0 49 iter->second.ofs->close();
Chris@0 50 delete iter->second.ofs;
Chris@0 51 }
Chris@0 52 }
Chris@0 53
Chris@0 54 // TODO: error handling on close
Chris@0 55 }
Chris@0 56
Chris@0 57 AudioDBFeatureWriter::ParameterList
Chris@0 58 AudioDBFeatureWriter::getSupportedParameters() const
Chris@0 59 {
Chris@0 60 ParameterList pl;
Chris@0 61 Parameter p;
Chris@0 62
Chris@0 63 p.name = catalogueIdParam;
Chris@0 64 p.description = "Catalogue ID";
Chris@0 65 p.hasArg = true;
Chris@0 66 pl.push_back(p);
Chris@0 67
Chris@0 68 p.name = baseDirParam;
Chris@0 69 p.description = "Base output directory path";
Chris@0 70 p.hasArg = true;
Chris@0 71 pl.push_back(p);
Chris@0 72
Chris@0 73 return pl;
Chris@0 74 }
Chris@0 75
Chris@0 76 void
Chris@0 77 AudioDBFeatureWriter::setParameters(map<string, string> &params)
Chris@0 78 {
Chris@0 79 if (params.find(catalogueIdParam) != params.end()) {
Chris@0 80 setCatalogueId(params[catalogueIdParam]);
Chris@0 81 params.erase(catalogueIdParam);
Chris@0 82 }
Chris@0 83 if (params.find(baseDirParam) != params.end()) {
Chris@0 84 setBaseDirectory(params[baseDirParam]);
Chris@0 85 params.erase(baseDirParam);
Chris@0 86 }
Chris@0 87 }
Chris@0 88
Chris@0 89 void
Chris@0 90 AudioDBFeatureWriter::setCatalogueId(const string &catid)
Chris@0 91 {
Chris@0 92 catalogueId = catid;
Chris@0 93 }
Chris@0 94
Chris@0 95 void
Chris@0 96 AudioDBFeatureWriter::setBaseDirectory(const string &base)
Chris@0 97 {
Chris@0 98 baseDir = base;
Chris@0 99 }
Chris@0 100
Chris@0 101 void AudioDBFeatureWriter::write(QString trackid,
Chris@0 102 const Transform &transform,
Chris@0 103 const Vamp::Plugin::OutputDescriptor& output,
Chris@0 104 const Vamp::Plugin::FeatureList& featureList,
Chris@0 105 std::string summaryType)
Chris@0 106 {
Chris@0 107 //!!! use summaryType
Chris@0 108 if (summaryType != "") {
Chris@0 109 //!!! IMPLEMENT
Chris@0 110 cerr << "ERROR: AudioDBFeatureWriter::write: Writing summaries is not yet implemented!" << endl;
Chris@0 111 exit(1);
Chris@0 112 }
Chris@0 113
Chris@0 114
Chris@0 115 // binary output for FeatureSet
Chris@0 116
Chris@0 117 // feature-dimension feature-1 feature-2 ...
Chris@0 118 // timestamp-1 timestamp-2 ...
Chris@0 119
Chris@0 120 // audioDB has to write each feature to a different file
Chris@0 121 // assume a simple naming convention of
Chris@0 122 // <catalog-id>/<track-id>.<feature-id>
Chris@0 123 // with timestamps in a corresponding <catalog-id>/<track-id>.<feature-id>.timestamp file
Chris@0 124 // (start and end times in seconds for each frame -- somewhat optional)
Chris@0 125
Chris@0 126 // the feature writer holds a map of open file descriptors
Chris@0 127 // the catalog-id is passed in to the feature writer's constructor
Chris@0 128
Chris@0 129 // NB -- all "floats" in the file should in fact be doubles
Chris@0 130
Chris@0 131 // TODO:
Chris@0 132 // - write feature end rather than start times, once end time is available in vamp
Chris@0 133 // - write a power file, probably by wrapping plugin in a PluginPowerAdapter :)
Chris@0 134
Chris@0 135 if (output.binCount == 0) // this kind of feature just outputs timestamps and labels, assume of no interest to audioDB
Chris@0 136 return;
Chris@0 137
Chris@0 138 for (int i = 0; i < featureList.size(); ++i)
Chris@0 139 {
Chris@0 140 // replace output files if necessary
Chris@0 141 if (replaceDBFile(trackid, output.identifier))
Chris@0 142 {
Chris@0 143 // write the feature length for the next track feature record
Chris@0 144 // binCount has to be set
Chris@0 145 // - it can be zero, i.e. if the output is really a set of labels + timestamps
Chris@0 146 *dbfiles[output.identifier].ofs /*<< ios::binary*/ << output.binCount;
Chris@0 147
Chris@0 148 cerr << "writing bin count " << output.binCount << " for " << output.identifier << endl;
Chris@0 149 }
Chris@0 150
Chris@0 151 if (replaceDBFile(trackid, output.identifier + ".timestamp"))
Chris@0 152 {
Chris@0 153 // write the start time to the timestamp file
Chris@0 154 // as we want it for the first feature in the file
Chris@0 155 *dbfiles[output.identifier + ".timestamp"].ofs << featureList[i].timestamp.toString() << endl;
Chris@0 156 }
Chris@0 157
Chris@0 158 if (dbfiles[output.identifier].ofs) {
Chris@0 159 for (int j = 0; j < featureList[i].values.size(); ++j)
Chris@0 160 *dbfiles[output.identifier].ofs /*<< ios::binary*/ << featureList[i].values[j];
Chris@0 161
Chris@0 162 // write the *end* time of each feature to the timestamp file
Chris@0 163 // NOT IMPLEMENTED YET
Chris@0 164 // *dbfiles[output.identifier + ".timestamp"].ofs << featureList[i].timestamp.toString() << endl;
Chris@0 165 }
Chris@0 166 }
Chris@0 167 }
Chris@0 168
Chris@0 169 bool AudioDBFeatureWriter::openDBFile(QString trackid, const string& identifier)
Chris@0 170 {
Chris@0 171 QString trackBase = QFileInfo(trackid).fileName();
Chris@0 172 string filepath = baseDir + "/" + catalogueId + "/"
Chris@0 173 + trackBase.toStdString() + "." + identifier;
Chris@0 174 cerr << "AudioDBFeatureWriter::openDBFile: filepath is \"" << filepath << "\"" << endl;
Chris@0 175 ofstream* ofs = new ofstream(filepath.c_str());
Chris@0 176 if (!*ofs)
Chris@0 177 {
Chris@0 178 cerr << "ERROR AudioDBFeatureWriter::openDBFile(): can't open file " << filepath << endl;
Chris@0 179 return false;
Chris@0 180 }
Chris@0 181 TrackStream ts;
Chris@0 182 ts.trackid = trackid;
Chris@0 183 ts.ofs = ofs;
Chris@0 184 dbfiles[identifier] = ts;
Chris@0 185 return true;
Chris@0 186 }
Chris@0 187
Chris@0 188 // replace file if no file open for this track, else return false
Chris@0 189 bool AudioDBFeatureWriter::replaceDBFile(QString trackid,
Chris@0 190 const string& identifier)
Chris@0 191 {
Chris@0 192 if (dbfiles.find(identifier) != dbfiles.end() && dbfiles[identifier].trackid == trackid)
Chris@0 193 return false; // have an open file for this track
Chris@0 194
Chris@0 195 if (dbfiles.find(identifier) != dbfiles.end() && dbfiles[identifier].trackid != trackid)
Chris@0 196 {
Chris@0 197 // close the current file
Chris@0 198 if (dbfiles[identifier].ofs) {
Chris@0 199 dbfiles[identifier].ofs->close();
Chris@0 200 delete dbfiles[identifier].ofs;
Chris@0 201 dbfiles[identifier].ofs = 0;
Chris@0 202 }
Chris@0 203 }
Chris@0 204
Chris@0 205 // open a new file
Chris@0 206 if (!openDBFile(trackid, identifier)) {
Chris@0 207 dbfiles[identifier].ofs = 0;
Chris@0 208 return false; //!!! should throw an exception, otherwise we'll try to open the file again and again every time we want to write to it
Chris@0 209 }
Chris@0 210
Chris@0 211 return true;
Chris@0 212 }
Chris@0 213
Chris@0 214