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