comparison test/processfile.cpp @ 119:a38d6940f8fb

Bring in dsp dependencies
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 15 May 2014 12:24:11 +0100
parents
children 8996465e39fc
comparison
equal deleted inserted replaced
118:36bfbc606642 119:a38d6940f8fb
1
2 #include "ConstantQ.h"
3 #include "CQInverse.h"
4
5 #include <sndfile.h>
6
7 #include <iostream>
8
9 using std::vector;
10 using std::cerr;
11 using std::endl;
12
13 #include <cstring>
14
15 #include <getopt.h>
16 #include <unistd.h>
17 #include <sys/time.h>
18 #include <cstdlib>
19
20 int main(int argc, char **argv)
21 {
22 double maxFreq = 0;
23 double minFreq = 0;
24 int bpo = 0;
25 bool help = false;
26
27 int c;
28
29 while (1) {
30 int optionIndex = 0;
31
32 static struct option longOpts[] = {
33 { "help", 0, 0, 'h', },
34 { "maxfreq", 1, 0, 'x', },
35 { "minfreq", 1, 0, 'n', },
36 { "bpo", 1, 0, 'b' },
37 { 0, 0, 0, 0 },
38 };
39
40 c = getopt_long(argc, argv,
41 "hx:n:b:",
42 longOpts, &optionIndex);
43 if (c == -1) break;
44
45 switch (c) {
46 case 'h': help = true; break;
47 case 'x': maxFreq = atof(optarg); break;
48 case 'n': minFreq = atof(optarg); break;
49 case 'b': bpo = atoi(optarg); break;
50 default: help = true; break;
51 }
52 }
53
54 if (help || (optind + 2 != argc && optind + 3 != argc)) {
55 cerr << endl;
56 cerr << "Usage: " << argv[0] << " [options] infile.wav outfile.wav [differencefile.wav]" << endl;
57 cerr << endl;
58 cerr << "Options:" << endl;
59 cerr << " -x<X>, --maxfreq <X> Maximum frequency (default = sample rate / 3)" << endl;
60 cerr << " -n<X>, --minfreq <X> Minimum frequency (default = 100, actual min may vary)" << endl;
61 cerr << " -b<X>, --bpo <X> Bins per octave (default = 60)" << endl;
62 cerr << " -h, --help Print this help" << endl;
63 cerr << endl;
64 cerr << "This rather useless program simply performs a forward Constant-Q transform with" << endl;
65 cerr << "the requested parameters, followed by its inverse, and writes the result to the" << endl;
66 cerr << "output file. If a diff file name is provided, the difference between input and" << endl;
67 cerr << "output signals is also written to that. All this accomplishes is to produce a" << endl;
68 cerr << "signal that approximates the input: it's intended for test purposes only." << endl;
69 cerr << endl;
70 cerr << "(Want to calculate and obtain a Constant-Q spectrogram? Use the CQVamp plugin" << endl;
71 cerr << "in a Vamp plugin host.)" << endl;
72 cerr << endl;
73 return 2;
74 }
75
76 char *fileName = strdup(argv[optind++]);
77 char *fileNameOut = strdup(argv[optind++]);
78 char *diffFileName = (optind < argc ? strdup(argv[optind++]) : 0);
79 bool doDiff = (diffFileName != 0);
80
81 SNDFILE *sndfile;
82 SNDFILE *sndfileOut;
83 SNDFILE *sndDiffFile = 0;
84 SF_INFO sfinfo;
85 SF_INFO sfinfoOut;
86 SF_INFO sfinfoDiff;
87 memset(&sfinfo, 0, sizeof(SF_INFO));
88
89 sndfile = sf_open(fileName, SFM_READ, &sfinfo);
90 if (!sndfile) {
91 cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
92 << sf_strerror(sndfile) << endl;
93 return 1;
94 }
95
96 sfinfoOut.channels = 1;
97 sfinfoOut.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
98 sfinfoOut.frames = sfinfo.frames;
99 sfinfoOut.samplerate = sfinfo.samplerate;
100 sfinfoOut.sections = sfinfo.sections;
101 sfinfoOut.seekable = sfinfo.seekable;
102
103 sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ;
104 if (!sndfileOut) {
105 cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
106 << sf_strerror(sndfileOut) << endl;
107 return 1;
108 }
109
110 if (doDiff) {
111 sfinfoDiff = sfinfoOut;
112 sndDiffFile = sf_open(diffFileName, SFM_WRITE, &sfinfoDiff);
113 if (!sndDiffFile) {
114 cerr << "ERROR: Failed to open diff output file \"" << diffFileName << "\" for writing: "
115 << sf_strerror(sndDiffFile) << endl;
116 return 1;
117 }
118 }
119
120 int ibs = 1024;
121 int channels = sfinfo.channels;
122 float *fbuf = new float[channels * ibs];
123
124 if (maxFreq == 0.0) maxFreq = sfinfo.samplerate / 3;
125 if (minFreq == 0.0) minFreq = 100;
126 if (bpo == 0) bpo = 60;
127
128 ConstantQ cq(sfinfo.samplerate, minFreq, maxFreq, bpo);
129 CQInverse cqi(sfinfo.samplerate, minFreq, maxFreq, bpo);
130
131 cerr << "max freq = " << cq.getMaxFrequency() << ", min freq = "
132 << cq.getMinFrequency() << ", octaves = " << cq.getOctaves() << endl;
133
134 cerr << "octave boundaries: ";
135 for (int i = 0; i < cq.getOctaves(); ++i) {
136 cerr << cq.getMaxFrequency() / pow(2, i) << " ";
137 }
138 cerr << endl;
139
140 int inframe = 0;
141 int outframe = 0;
142 int latency = cq.getLatency() + cqi.getLatency();
143
144 vector<double> buffer;
145
146 double maxdiff = 0.0;
147 int maxdiffidx = 0;
148
149 cerr << "forward latency = " << cq.getLatency() << ", inverse latency = "
150 << cqi.getLatency() << ", total = " << latency << endl;
151
152 timeval tv;
153 (void)gettimeofday(&tv, 0);
154
155 while (inframe < sfinfo.frames) {
156
157 int count = -1;
158
159 if ((count = sf_readf_float(sndfile, fbuf, ibs)) < 0) {
160 break;
161 }
162
163 vector<double> cqin;
164 for (int i = 0; i < count; ++i) {
165 double v = fbuf[i * channels];
166 if (channels > 1) {
167 for (int c = 1; c < channels; ++c) {
168 v += fbuf[i * channels + c];
169 }
170 v /= channels;
171 }
172 cqin.push_back(v);
173 }
174
175 if (doDiff) {
176 buffer.insert(buffer.end(), cqin.begin(), cqin.end());
177 }
178
179 vector<double> cqout = cqi.process(cq.process(cqin));
180
181 for (int i = 0; i < int(cqout.size()); ++i) {
182 if (cqout[i] > 1.0) cqout[i] = 1.0;
183 if (cqout[i] < -1.0) cqout[i] = -1.0;
184 }
185
186 if (outframe >= latency) {
187
188 sf_writef_double(sndfileOut,
189 cqout.data(),
190 cqout.size());
191
192 } else if (outframe + (int)cqout.size() >= latency) {
193
194 int offset = latency - outframe;
195 sf_writef_double(sndfileOut,
196 cqout.data() + offset,
197 cqout.size() - offset);
198 }
199
200 if (doDiff) {
201 for (int i = 0; i < (int)cqout.size(); ++i) {
202 if (outframe + i >= latency) {
203 int dframe = outframe + i - latency;
204 if (dframe >= (int)buffer.size()) cqout[i] = 0;
205 else cqout[i] -= buffer[dframe];
206 if (fabs(cqout[i]) > maxdiff &&
207 dframe > sfinfo.samplerate && // ignore first/last sec
208 dframe + sfinfo.samplerate < sfinfo.frames) {
209 maxdiff = fabs(cqout[i]);
210 maxdiffidx = dframe;
211 }
212 }
213 }
214
215 if (outframe >= latency) {
216
217 sf_writef_double(sndDiffFile,
218 cqout.data(),
219 cqout.size());
220
221 } else if (outframe + (int)cqout.size() >= latency) {
222
223 int offset = latency - outframe;
224 sf_writef_double(sndDiffFile,
225 cqout.data() + offset,
226 cqout.size() - offset);
227 }
228 }
229
230 inframe += count;
231 outframe += cqout.size();
232 }
233
234 vector<double> r = cqi.process(cq.getRemainingOutput());
235 vector<double> r2 = cqi.getRemainingOutput();
236
237 r.insert(r.end(), r2.begin(), r2.end());
238
239 for (int i = 0; i < int(r.size()); ++i) {
240 if (r[i] > 1.0) r[i] = 1.0;
241 if (r[i] < -1.0) r[i] = -1.0;
242 }
243
244 sf_writef_double(sndfileOut, r.data(), r.size());
245 if (doDiff) {
246 for (int i = 0; i < (int)r.size(); ++i) {
247 if (outframe + i >= latency) {
248 int dframe = outframe + i - latency;
249 if (dframe >= (int)buffer.size()) r[i] = 0;
250 else r[i] -= buffer[dframe];
251 if (fabs(r[i]) > maxdiff &&
252 dframe > sfinfo.samplerate && // ignore first/last sec
253 dframe + sfinfo.samplerate < sfinfo.frames) {
254 maxdiff = fabs(r[i]);
255 maxdiffidx = dframe;
256 }
257 }
258 }
259 sf_writef_double(sndDiffFile, r.data(), r.size());
260 }
261 outframe += r.size();
262
263 sf_close(sndfile);
264 sf_close(sndfileOut);
265
266 if (doDiff) {
267 sf_close(sndDiffFile);
268 }
269
270 cerr << "in: " << inframe << ", out: " << outframe - latency << endl;
271
272 if (doDiff) {
273 double db = 10 * log10(maxdiff);
274 cerr << "max diff [excluding first and last second of audio] is "
275 << maxdiff << " (" << db << " dBFS)"
276 << " at sample index " << maxdiffidx << endl;
277 }
278
279 timeval etv;
280 (void)gettimeofday(&etv, 0);
281
282 etv.tv_sec -= tv.tv_sec;
283 if (etv.tv_usec < tv.tv_usec) {
284 etv.tv_usec += 1000000;
285 etv.tv_sec -= 1;
286 }
287 etv.tv_usec -= tv.tv_usec;
288
289 double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
290 cerr << "elapsed time (not counting init): " << sec << " sec, frames/sec at input: " << inframe/sec << endl;
291
292 return 0;
293 }
294