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