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