comparison garage-resampler/resample.cpp @ 12:1879a2997ebf

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