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

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