Mercurial > hg > constant-q-cpp
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 |