annotate constant-q-cpp/test/processfile.cpp @ 372:af71cbdab621 tip

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