Mercurial > hg > decimation
view 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 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #include "qm-dsp/dsp/rateconversion/Resampler.h" #include <iostream> #include <sndfile.h> #include <time.h> #include <string> #include <cstdlib> #include <cstring> #include <cmath> #include <getopt.h> #include <unistd.h> #include <sys/time.h> using namespace std; int main(int argc, char **argv) { int targetRate = 0; bool version = false; bool help = false; double snr = 100; double bandwidth = 0.02; int c = 0; while (1) { int optionIndex = 0; static struct option longOpts[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, { "to", 1, 0, 't' }, { "snr", 1, 0, 's' }, { "bandwidth", 1, 0, 'b' }, { 0, 0, 0, 0 } }; c = getopt_long(argc, argv, "t:hVs:b:", longOpts, &optionIndex); if (c == -1) break; switch (c) { case 'h': help = true; break; case 'V': version = true; break; case 't': targetRate = atoi(optarg); break; case 's': snr = atof(optarg); break; case 'b': bandwidth = atof(optarg); break; default: help = true; break; } } if (version) { cerr << "resample v0.1" << endl; //!!! return 0; } if (help || targetRate == 0 || optind + 2 != argc) { cerr << endl; cerr << "usage: " << argv[0] << " --to <rate> [--snr <s>] [--bandwidth <b>] <infile.wav> <outfile.wav>" << endl; cerr << endl; return 2; } timeval tv; (void)gettimeofday(&tv, 0); char *fileName = strdup(argv[optind++]); char *fileNameOut = strdup(argv[optind++]); SNDFILE *sndfile; SNDFILE *sndfileOut; SF_INFO sfinfo; SF_INFO sfinfoOut; memset(&sfinfo, 0, sizeof(SF_INFO)); sndfile = sf_open(fileName, SFM_READ, &sfinfo); if (!sndfile) { cerr << "ERROR: Failed to open input file \"" << fileName << "\": " << sf_strerror(sndfile) << endl; return 1; } int sourceRate = sfinfo.samplerate; sfinfoOut.channels = sfinfo.channels; sfinfoOut.format = sfinfo.format; sfinfoOut.frames = int(ceil(double(sfinfo.frames) * targetRate) / sourceRate); sfinfoOut.samplerate = targetRate; sfinfoOut.sections = sfinfo.sections; sfinfoOut.seekable = sfinfo.seekable; sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut); if (!sndfileOut) { cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: " << sf_strerror(sndfileOut) << endl; return 1; } int channels = sfinfo.channels; vector<Resampler *> resamplers; // one per channel cerr << "Resampling from " << sourceRate << " to " << targetRate << " Hz [with snr " << snr << ", bandwidth " << bandwidth << "]" << endl; for (int c = 0; c < channels; ++c) { resamplers.push_back (new Resampler(sourceRate, targetRate, snr, bandwidth)); } int outputLatency = resamplers[0]->getLatency(); int inputLatency = int(ceil((double(outputLatency) * sourceRate) / targetRate)); int ibs = 1024; if (ibs < inputLatency) { ibs = inputLatency; } int obs = int(ceil((double(ibs) * targetRate) / sourceRate)); float *ibuf = new float[channels * ibs]; float *obuf = new float[channels * obs]; double **prebuf = new double*[channels]; double **postbuf = new double*[channels]; for (int c = 0; c < channels; ++c) { prebuf[c] = new double[ibs]; postbuf[c] = new double[obs]; } int n = 0; int rcount = 0; int ocount = 0; while (true) { int count = sf_readf_float(sndfile, ibuf, ibs); if (count <= 0) break; rcount = 0; ocount = 0; for (int c = 0; c < channels; ++c) { for (int i = 0; i < count; ++i) { prebuf[c][i] = ibuf[i * channels + c]; } rcount = resamplers[c]->process(prebuf[c], postbuf[c], count); if (n + rcount > outputLatency) { int off = 0; if (outputLatency > n) { off = outputLatency - n; } for (int i = off; i < rcount; ++i) { obuf[(i - off) * channels + c] = postbuf[c][i]; } ocount = rcount - off; } } if (ocount > 0) { sf_writef_float(sndfileOut, obuf, ocount); } n += rcount; } // latency tail for (int c = 0; c < channels; ++c) { for (int i = 0; i < inputLatency; ++i) { prebuf[c][i] = 0.0; } rcount = resamplers[c]->process(prebuf[c], postbuf[c], inputLatency); for (int i = 0; i < rcount; ++i) { obuf[i * channels + c] = postbuf[c][i]; } } sf_writef_float(sndfileOut, obuf, outputLatency); n += outputLatency; sf_close(sndfile); sf_close(sndfileOut); for (int c = 0; c < channels; ++c) { delete[] prebuf[c]; delete[] postbuf[c]; delete resamplers[c]; } delete[] prebuf; delete[] postbuf; delete[] ibuf; delete[] obuf; timeval etv; (void)gettimeofday(&etv, 0); etv.tv_sec -= tv.tv_sec; if (etv.tv_usec < tv.tv_usec) { etv.tv_usec += 1000000; etv.tv_sec -= 1; } etv.tv_usec -= tv.tv_usec; double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0); cerr << sfinfo.frames << " frames in, " << n << " frames out" << ", nominal ratio " << double(targetRate)/double(sourceRate) << ", actual " << double(n)/double(sfinfo.frames) << endl << "Elapsed time: " << sec << " sec, in frames/sec: " << int(sfinfo.frames/sec) << ", out frames/sec: " << int(n/sec) << endl; return 0; }