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