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