annotate qm-dsp-decimate/decimate.cpp @ 15:e35d83f7b4f0

Add command line program for qm-dsp decimator
author Chris Cannam
date Fri, 18 Oct 2013 13:08:00 +0100
parents garage-resampler/resample.cpp@8c87484e6d79
children f8efad075df0
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@15 3 #include "qm-dsp/dsp/rateconversion/Decimator.h"
Chris@15 4 #include "qm-dsp/maths/MathUtilities.h"
Chris@12 5
Chris@12 6 #include <iostream>
Chris@12 7 #include <sndfile.h>
Chris@12 8 #include <time.h>
Chris@12 9 #include <string>
Chris@12 10 #include <cstdlib>
Chris@12 11 #include <cstring>
Chris@12 12 #include <cmath>
Chris@12 13 #include <getopt.h>
Chris@12 14 #include <unistd.h>
Chris@12 15 #include <sys/time.h>
Chris@12 16
Chris@12 17 using namespace std;
Chris@12 18
Chris@12 19 int main(int argc, char **argv)
Chris@12 20 {
Chris@15 21 int factor = 0;
Chris@12 22 bool version = false;
Chris@12 23 bool help = false;
Chris@12 24 int c = 0;
Chris@12 25
Chris@12 26 while (1) {
Chris@12 27 int optionIndex = 0;
Chris@12 28
Chris@12 29 static struct option longOpts[] = {
Chris@12 30 { "help", 0, 0, 'h' },
Chris@12 31 { "version", 0, 0, 'V' },
Chris@15 32 { "by", 1, 0, 'b' },
Chris@12 33 { 0, 0, 0, 0 }
Chris@12 34 };
Chris@12 35
Chris@12 36 c = getopt_long(argc, argv,
Chris@15 37 "b:hV",
Chris@12 38 longOpts, &optionIndex);
Chris@12 39 if (c == -1) break;
Chris@12 40
Chris@12 41 switch (c) {
Chris@12 42 case 'h': help = true; break;
Chris@12 43 case 'V': version = true; break;
Chris@15 44 case 'b': factor = atoi(optarg); break;
Chris@12 45 default: help = true; break;
Chris@12 46 }
Chris@12 47 }
Chris@12 48
Chris@12 49 if (version) {
Chris@15 50 cerr << "decimate v0.1" << endl; //!!!
Chris@12 51 return 0;
Chris@12 52 }
Chris@12 53
Chris@15 54 if (help || factor == 0 || optind + 2 != argc) {
Chris@12 55 cerr << endl;
Chris@15 56 cerr << "usage: " << argv[0] << " --by <factor> <infile.wav> <outfile.wav>" << endl;
Chris@12 57 cerr << endl;
Chris@12 58 return 2;
Chris@12 59 }
Chris@15 60
Chris@15 61 if (!MathUtilities::isPowerOfTwo(factor)) {
Chris@15 62 cerr << "ERROR: Factor must be a power of two" << endl;
Chris@15 63 return 1;
Chris@15 64 }
Chris@15 65 if (factor < 2 || factor > Decimator::getHighestSupportedFactor()) {
Chris@15 66 cerr << "ERROR: Only factors between 2 and "
Chris@15 67 << Decimator::getHighestSupportedFactor()
Chris@15 68 << " inclusive are supported" <<endl;
Chris@15 69 return 1;
Chris@15 70 }
Chris@12 71
Chris@12 72 timeval tv;
Chris@12 73 (void)gettimeofday(&tv, 0);
Chris@12 74
Chris@12 75 char *fileName = strdup(argv[optind++]);
Chris@12 76 char *fileNameOut = strdup(argv[optind++]);
Chris@12 77
Chris@12 78 SNDFILE *sndfile;
Chris@12 79 SNDFILE *sndfileOut;
Chris@12 80 SF_INFO sfinfo;
Chris@12 81 SF_INFO sfinfoOut;
Chris@12 82 memset(&sfinfo, 0, sizeof(SF_INFO));
Chris@12 83
Chris@12 84 sndfile = sf_open(fileName, SFM_READ, &sfinfo);
Chris@12 85 if (!sndfile) {
Chris@12 86 cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
Chris@12 87 << sf_strerror(sndfile) << endl;
Chris@12 88 return 1;
Chris@12 89 }
Chris@12 90
Chris@12 91 int sourceRate = sfinfo.samplerate;
Chris@15 92 int targetRate = sourceRate / factor;
Chris@15 93
Chris@15 94 if (sourceRate % factor != 0) {
Chris@15 95 cerr << "WARNING: Decimation factor " << factor << " from source rate "
Chris@15 96 << sourceRate << " gives non-integral target rate (not supported "
Chris@15 97 << "by output file format), recording as " << targetRate << endl;
Chris@15 98 }
Chris@12 99
Chris@12 100 sfinfoOut.channels = sfinfo.channels;
Chris@12 101 sfinfoOut.format = sfinfo.format;
Chris@15 102 sfinfoOut.frames = sfinfo.frames / factor;
Chris@12 103 sfinfoOut.samplerate = targetRate;
Chris@12 104 sfinfoOut.sections = sfinfo.sections;
Chris@12 105 sfinfoOut.seekable = sfinfo.seekable;
Chris@12 106
Chris@12 107 sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut);
Chris@12 108 if (!sndfileOut) {
Chris@12 109 cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
Chris@12 110 << sf_strerror(sndfileOut) << endl;
Chris@12 111 return 1;
Chris@12 112 }
Chris@13 113
Chris@13 114 int channels = sfinfo.channels;
Chris@15 115 vector<Decimator *> decimators; // one per channel
Chris@15 116
Chris@15 117 int ibs = 1024;
Chris@15 118 int obs = ibs / factor;
Chris@13 119
Chris@13 120 for (int c = 0; c < channels; ++c) {
Chris@15 121 decimators.push_back(new Decimator(ibs, factor));
Chris@13 122 }
Chris@13 123
Chris@12 124 float *ibuf = new float[channels * ibs];
Chris@12 125 float *obuf = new float[channels * obs];
Chris@12 126
Chris@12 127 double **prebuf = new double*[channels];
Chris@12 128 double **postbuf = new double*[channels];
Chris@12 129
Chris@12 130 for (int c = 0; c < channels; ++c) {
Chris@12 131 prebuf[c] = new double[ibs];
Chris@12 132 postbuf[c] = new double[obs];
Chris@12 133 }
Chris@12 134
Chris@12 135 int n = 0;
Chris@12 136
Chris@12 137 while (true) {
Chris@12 138
Chris@12 139 int count = sf_readf_float(sndfile, ibuf, ibs);
Chris@12 140 if (count <= 0) break;
Chris@12 141
Chris@12 142 for (int c = 0; c < channels; ++c) {
Chris@12 143
Chris@12 144 for (int i = 0; i < count; ++i) {
Chris@12 145 prebuf[c][i] = ibuf[i * channels + c];
Chris@12 146 }
Chris@15 147 for (int i = count; i < ibs; ++i) {
Chris@15 148 prebuf[c][i] = 0.0;
Chris@15 149 }
Chris@12 150
Chris@15 151 decimators[c]->process(prebuf[c], postbuf[c]);
Chris@12 152
Chris@15 153 for (int i = 0; i < obs; ++i) {
Chris@15 154 obuf[i * channels + c] = postbuf[c][i];
Chris@15 155 }
Chris@12 156 }
Chris@12 157
Chris@15 158 int ocount = obs;
Chris@15 159 if (count < ibs) {
Chris@15 160 ocount = count / factor;
Chris@15 161 }
Chris@15 162
Chris@15 163 sf_writef_float(sndfileOut, obuf, ocount);
Chris@15 164
Chris@15 165 n += ocount;
Chris@12 166 }
Chris@12 167
Chris@12 168 sf_close(sndfile);
Chris@12 169 sf_close(sndfileOut);
Chris@12 170
Chris@12 171 for (int c = 0; c < channels; ++c) {
Chris@12 172 delete[] prebuf[c];
Chris@12 173 delete[] postbuf[c];
Chris@15 174 delete decimators[c];
Chris@12 175 }
Chris@12 176
Chris@12 177 delete[] prebuf;
Chris@12 178 delete[] postbuf;
Chris@12 179 delete[] ibuf;
Chris@12 180 delete[] obuf;
Chris@12 181
Chris@12 182 timeval etv;
Chris@12 183 (void)gettimeofday(&etv, 0);
Chris@12 184
Chris@12 185 etv.tv_sec -= tv.tv_sec;
Chris@12 186 if (etv.tv_usec < tv.tv_usec) {
Chris@12 187 etv.tv_usec += 1000000;
Chris@12 188 etv.tv_sec -= 1;
Chris@12 189 }
Chris@12 190 etv.tv_usec -= tv.tv_usec;
Chris@12 191
Chris@12 192 double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
Chris@12 193 cerr << "elapsed time: " << sec << " sec, in frames/sec: " << sfinfo.frames/sec << ", out frames/sec: " << n/sec << endl;
Chris@12 194
Chris@12 195 return 0;
Chris@12 196 }
Chris@12 197
Chris@12 198
Chris@12 199
Chris@12 200
Chris@12 201
Chris@12 202