annotate qm-dsp-resample/resample.cpp @ 28:69ee50c19c0c tip

Add decimate-b
author Chris Cannam
date Tue, 22 Oct 2013 08:59:42 +0100
parents 20ed07459176
children
rev   line source
Chris@12 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@12 2
Chris@26 3 #include "qm-dsp/dsp/rateconversion/Resampler.h"
Chris@12 4
Chris@12 5 #include <iostream>
Chris@12 6 #include <sndfile.h>
Chris@12 7 #include <time.h>
Chris@12 8 #include <string>
Chris@12 9 #include <cstdlib>
Chris@12 10 #include <cstring>
Chris@12 11 #include <cmath>
Chris@12 12 #include <getopt.h>
Chris@12 13 #include <unistd.h>
Chris@12 14 #include <sys/time.h>
Chris@12 15
Chris@12 16 using namespace std;
Chris@12 17
Chris@12 18 int main(int argc, char **argv)
Chris@12 19 {
Chris@12 20 int targetRate = 0;
Chris@12 21 bool version = false;
Chris@12 22 bool help = false;
Chris@16 23 double snr = 100;
Chris@16 24 double bandwidth = 0.02;
Chris@12 25 int c = 0;
Chris@12 26
Chris@12 27 while (1) {
Chris@12 28 int optionIndex = 0;
Chris@12 29
Chris@12 30 static struct option longOpts[] = {
Chris@12 31 { "help", 0, 0, 'h' },
Chris@12 32 { "version", 0, 0, 'V' },
Chris@12 33 { "to", 1, 0, 't' },
Chris@16 34 { "snr", 1, 0, 's' },
Chris@16 35 { "bandwidth", 1, 0, 'b' },
Chris@12 36 { 0, 0, 0, 0 }
Chris@12 37 };
Chris@12 38
Chris@12 39 c = getopt_long(argc, argv,
Chris@16 40 "t:hVs:b:",
Chris@12 41 longOpts, &optionIndex);
Chris@12 42 if (c == -1) break;
Chris@12 43
Chris@12 44 switch (c) {
Chris@12 45 case 'h': help = true; break;
Chris@12 46 case 'V': version = true; break;
Chris@12 47 case 't': targetRate = atoi(optarg); break;
Chris@16 48 case 's': snr = atof(optarg); break;
Chris@16 49 case 'b': bandwidth = atof(optarg); break;
Chris@12 50 default: help = true; break;
Chris@12 51 }
Chris@12 52 }
Chris@12 53
Chris@12 54 if (version) {
Chris@12 55 cerr << "resample v0.1" << endl; //!!!
Chris@12 56 return 0;
Chris@12 57 }
Chris@12 58
Chris@12 59 if (help || targetRate == 0 || optind + 2 != argc) {
Chris@12 60 cerr << endl;
Chris@16 61 cerr << "usage: " << argv[0] << " --to <rate> [--snr <s>] [--bandwidth <b>] <infile.wav> <outfile.wav>" << endl;
Chris@12 62 cerr << endl;
Chris@12 63 return 2;
Chris@12 64 }
Chris@12 65
Chris@12 66 timeval tv;
Chris@12 67 (void)gettimeofday(&tv, 0);
Chris@12 68
Chris@12 69 char *fileName = strdup(argv[optind++]);
Chris@12 70 char *fileNameOut = strdup(argv[optind++]);
Chris@12 71
Chris@12 72 SNDFILE *sndfile;
Chris@12 73 SNDFILE *sndfileOut;
Chris@12 74 SF_INFO sfinfo;
Chris@12 75 SF_INFO sfinfoOut;
Chris@12 76 memset(&sfinfo, 0, sizeof(SF_INFO));
Chris@12 77
Chris@12 78 sndfile = sf_open(fileName, SFM_READ, &sfinfo);
Chris@12 79 if (!sndfile) {
Chris@12 80 cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
Chris@12 81 << sf_strerror(sndfile) << endl;
Chris@12 82 return 1;
Chris@12 83 }
Chris@12 84
Chris@12 85 int sourceRate = sfinfo.samplerate;
Chris@12 86
Chris@12 87 sfinfoOut.channels = sfinfo.channels;
Chris@12 88 sfinfoOut.format = sfinfo.format;
Chris@12 89 sfinfoOut.frames = int(ceil(double(sfinfo.frames) * targetRate) /
Chris@12 90 sourceRate);
Chris@12 91 sfinfoOut.samplerate = targetRate;
Chris@12 92 sfinfoOut.sections = sfinfo.sections;
Chris@12 93 sfinfoOut.seekable = sfinfo.seekable;
Chris@12 94
Chris@12 95 sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut);
Chris@12 96 if (!sndfileOut) {
Chris@12 97 cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
Chris@12 98 << sf_strerror(sndfileOut) << endl;
Chris@12 99 return 1;
Chris@12 100 }
Chris@13 101
Chris@13 102 int channels = sfinfo.channels;
Chris@13 103 vector<Resampler *> resamplers; // one per channel
Chris@13 104
Chris@16 105 cerr << "Resampling from " << sourceRate << " to " << targetRate
Chris@16 106 << " Hz [with snr " << snr << ", bandwidth " << bandwidth << "]"
Chris@16 107 << endl;
Chris@16 108
Chris@13 109 for (int c = 0; c < channels; ++c) {
Chris@16 110 resamplers.push_back
Chris@16 111 (new Resampler(sourceRate, targetRate, snr, bandwidth));
Chris@13 112 }
Chris@13 113
Chris@13 114 int outputLatency = resamplers[0]->getLatency();
Chris@13 115 int inputLatency = int(ceil((double(outputLatency) * sourceRate) /
Chris@13 116 targetRate));
Chris@12 117
Chris@12 118 int ibs = 1024;
Chris@13 119 if (ibs < inputLatency) {
Chris@13 120 ibs = inputLatency;
Chris@13 121 }
Chris@13 122
Chris@12 123 int obs = int(ceil((double(ibs) * targetRate) / sourceRate));
Chris@12 124
Chris@12 125 float *ibuf = new float[channels * ibs];
Chris@12 126 float *obuf = new float[channels * obs];
Chris@12 127
Chris@12 128 double **prebuf = new double*[channels];
Chris@12 129 double **postbuf = new double*[channels];
Chris@12 130
Chris@12 131 for (int c = 0; c < channels; ++c) {
Chris@12 132 prebuf[c] = new double[ibs];
Chris@12 133 postbuf[c] = new double[obs];
Chris@12 134 }
Chris@12 135
Chris@12 136 int n = 0;
Chris@13 137 int rcount = 0;
Chris@13 138 int ocount = 0;
Chris@12 139
Chris@12 140 while (true) {
Chris@12 141
Chris@12 142 int count = sf_readf_float(sndfile, ibuf, ibs);
Chris@12 143 if (count <= 0) break;
Chris@12 144
Chris@13 145 rcount = 0;
Chris@13 146 ocount = 0;
Chris@12 147
Chris@12 148 for (int c = 0; c < channels; ++c) {
Chris@12 149
Chris@12 150 for (int i = 0; i < count; ++i) {
Chris@12 151 prebuf[c][i] = ibuf[i * channels + c];
Chris@12 152 }
Chris@12 153
Chris@12 154 rcount = resamplers[c]->process(prebuf[c], postbuf[c], count);
Chris@12 155
Chris@13 156 if (n + rcount > outputLatency) {
Chris@12 157 int off = 0;
Chris@13 158 if (outputLatency > n) {
Chris@13 159 off = outputLatency - n;
Chris@12 160 }
Chris@12 161 for (int i = off; i < rcount; ++i) {
Chris@12 162 obuf[(i - off) * channels + c] = postbuf[c][i];
Chris@12 163 }
Chris@12 164 ocount = rcount - off;
Chris@12 165 }
Chris@12 166 }
Chris@12 167
Chris@12 168 if (ocount > 0) {
Chris@12 169 sf_writef_float(sndfileOut, obuf, ocount);
Chris@12 170 }
Chris@12 171
Chris@12 172 n += rcount;
Chris@12 173 }
Chris@12 174
Chris@13 175 // latency tail
Chris@13 176 for (int c = 0; c < channels; ++c) {
Chris@13 177 for (int i = 0; i < inputLatency; ++i) {
Chris@13 178 prebuf[c][i] = 0.0;
Chris@13 179 }
Chris@13 180 rcount = resamplers[c]->process(prebuf[c], postbuf[c], inputLatency);
Chris@13 181 for (int i = 0; i < rcount; ++i) {
Chris@13 182 obuf[i * channels + c] = postbuf[c][i];
Chris@13 183 }
Chris@13 184 }
Chris@14 185 sf_writef_float(sndfileOut, obuf, outputLatency);
Chris@14 186 n += outputLatency;
Chris@12 187
Chris@12 188 sf_close(sndfile);
Chris@12 189 sf_close(sndfileOut);
Chris@12 190
Chris@12 191 for (int c = 0; c < channels; ++c) {
Chris@12 192 delete[] prebuf[c];
Chris@12 193 delete[] postbuf[c];
Chris@12 194 delete resamplers[c];
Chris@12 195 }
Chris@12 196
Chris@12 197 delete[] prebuf;
Chris@12 198 delete[] postbuf;
Chris@12 199 delete[] ibuf;
Chris@12 200 delete[] obuf;
Chris@12 201
Chris@12 202 timeval etv;
Chris@12 203 (void)gettimeofday(&etv, 0);
Chris@12 204
Chris@12 205 etv.tv_sec -= tv.tv_sec;
Chris@12 206 if (etv.tv_usec < tv.tv_usec) {
Chris@12 207 etv.tv_usec += 1000000;
Chris@12 208 etv.tv_sec -= 1;
Chris@12 209 }
Chris@12 210 etv.tv_usec -= tv.tv_usec;
Chris@12 211
Chris@12 212 double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
Chris@16 213 cerr << sfinfo.frames << " frames in, " << n << " frames out"
Chris@16 214 << ", nominal ratio " << double(targetRate)/double(sourceRate)
Chris@16 215 << ", actual " << double(n)/double(sfinfo.frames)
Chris@16 216 << endl << "Elapsed time: " << sec << " sec, in frames/sec: "
Chris@16 217 << int(sfinfo.frames/sec) << ", out frames/sec: " << int(n/sec) << endl;
Chris@12 218
Chris@12 219 return 0;
Chris@12 220 }
Chris@12 221
Chris@12 222
Chris@12 223
Chris@12 224
Chris@12 225
Chris@12 226