cannam@95
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@95
|
2
|
cannam@95
|
3 /*
|
cannam@95
|
4 Rubber Band Library
|
cannam@95
|
5 An audio time-stretching and pitch-shifting library.
|
cannam@95
|
6 Copyright 2007-2012 Particular Programs Ltd.
|
cannam@95
|
7
|
cannam@95
|
8 This program is free software; you can redistribute it and/or
|
cannam@95
|
9 modify it under the terms of the GNU General Public License as
|
cannam@95
|
10 published by the Free Software Foundation; either version 2 of the
|
cannam@95
|
11 License, or (at your option) any later version. See the file
|
cannam@95
|
12 COPYING included with this distribution for more information.
|
cannam@95
|
13
|
cannam@95
|
14 Alternatively, if you have a valid commercial licence for the
|
cannam@95
|
15 Rubber Band Library obtained by agreement with the copyright
|
cannam@95
|
16 holders, you may redistribute and/or modify it under the terms
|
cannam@95
|
17 described in that licence.
|
cannam@95
|
18
|
cannam@95
|
19 If you wish to distribute code using the Rubber Band Library
|
cannam@95
|
20 under terms other than those of the GNU General Public License,
|
cannam@95
|
21 you must obtain a valid commercial licence before doing so.
|
cannam@95
|
22 */
|
cannam@95
|
23
|
cannam@95
|
24 #include "rubberband/RubberBandStretcher.h"
|
cannam@95
|
25
|
cannam@95
|
26 #include <iostream>
|
cannam@95
|
27 #include <sndfile.h>
|
cannam@95
|
28 #include <cmath>
|
cannam@95
|
29 #include <time.h>
|
cannam@95
|
30 #include <cstdlib>
|
cannam@95
|
31 #include <cstring>
|
cannam@95
|
32 #include <string>
|
cannam@95
|
33
|
cannam@95
|
34 #include <fstream>
|
cannam@95
|
35
|
cannam@95
|
36 #include "system/sysutils.h"
|
cannam@95
|
37
|
cannam@95
|
38 #ifdef __MSVC__
|
cannam@95
|
39 #include "getopt/getopt.h"
|
cannam@95
|
40 #else
|
cannam@95
|
41 #include <getopt.h>
|
cannam@95
|
42 #include <unistd.h>
|
cannam@95
|
43 #include <sys/time.h>
|
cannam@95
|
44 #endif
|
cannam@95
|
45
|
cannam@95
|
46 #include "base/Profiler.h"
|
cannam@95
|
47
|
cannam@95
|
48 using namespace std;
|
cannam@95
|
49 using namespace RubberBand;
|
cannam@95
|
50
|
cannam@95
|
51 #ifdef _WIN32
|
cannam@95
|
52 using RubberBand::gettimeofday;
|
cannam@95
|
53 #endif
|
cannam@95
|
54
|
cannam@95
|
55 #ifdef __MSVC__
|
cannam@95
|
56 using RubberBand::usleep;
|
cannam@95
|
57 #endif
|
cannam@95
|
58
|
cannam@95
|
59 double tempo_convert(const char *str)
|
cannam@95
|
60 {
|
cannam@95
|
61 char *d = strchr((char *)str, ':');
|
cannam@95
|
62
|
cannam@95
|
63 if (!d || !*d) {
|
cannam@95
|
64 double m = atof(str);
|
cannam@95
|
65 if (m != 0.0) return 1.0 / m;
|
cannam@95
|
66 else return 1.0;
|
cannam@95
|
67 }
|
cannam@95
|
68
|
cannam@95
|
69 char *a = strdup(str);
|
cannam@95
|
70 char *b = strdup(d+1);
|
cannam@95
|
71 a[d-str] = '\0';
|
cannam@95
|
72 double m = atof(a);
|
cannam@95
|
73 double n = atof(b);
|
cannam@95
|
74 free(a);
|
cannam@95
|
75 free(b);
|
cannam@95
|
76 if (n != 0.0 && m != 0.0) return m / n;
|
cannam@95
|
77 else return 1.0;
|
cannam@95
|
78 }
|
cannam@95
|
79
|
cannam@95
|
80 int main(int argc, char **argv)
|
cannam@95
|
81 {
|
cannam@95
|
82 int c;
|
cannam@95
|
83
|
cannam@95
|
84 double ratio = 1.0;
|
cannam@95
|
85 double duration = 0.0;
|
cannam@95
|
86 double pitchshift = 0.0;
|
cannam@95
|
87 double frequencyshift = 1.0;
|
cannam@95
|
88 int debug = 0;
|
cannam@95
|
89 bool realtime = false;
|
cannam@95
|
90 bool precise = true;
|
cannam@95
|
91 int threading = 0;
|
cannam@95
|
92 bool lamination = true;
|
cannam@95
|
93 bool longwin = false;
|
cannam@95
|
94 bool shortwin = false;
|
cannam@95
|
95 bool smoothing = false;
|
cannam@95
|
96 bool hqpitch = false;
|
cannam@95
|
97 bool formant = false;
|
cannam@95
|
98 bool together = false;
|
cannam@95
|
99 bool crispchanged = false;
|
cannam@95
|
100 int crispness = -1;
|
cannam@95
|
101 bool help = false;
|
cannam@95
|
102 bool version = false;
|
cannam@95
|
103 bool quiet = false;
|
cannam@95
|
104
|
cannam@95
|
105 bool haveRatio = false;
|
cannam@95
|
106
|
cannam@95
|
107 std::string mapfile;
|
cannam@95
|
108
|
cannam@95
|
109 enum {
|
cannam@95
|
110 NoTransients,
|
cannam@95
|
111 BandLimitedTransients,
|
cannam@95
|
112 Transients
|
cannam@95
|
113 } transients = Transients;
|
cannam@95
|
114
|
cannam@95
|
115 enum {
|
cannam@95
|
116 CompoundDetector,
|
cannam@95
|
117 PercussiveDetector,
|
cannam@95
|
118 SoftDetector
|
cannam@95
|
119 } detector = CompoundDetector;
|
cannam@95
|
120
|
cannam@95
|
121 while (1) {
|
cannam@95
|
122 int optionIndex = 0;
|
cannam@95
|
123
|
cannam@95
|
124 static struct option longOpts[] = {
|
cannam@95
|
125 { "help", 0, 0, 'h' },
|
cannam@95
|
126 { "version", 0, 0, 'V' },
|
cannam@95
|
127 { "time", 1, 0, 't' },
|
cannam@95
|
128 { "tempo", 1, 0, 'T' },
|
cannam@95
|
129 { "duration", 1, 0, 'D' },
|
cannam@95
|
130 { "pitch", 1, 0, 'p' },
|
cannam@95
|
131 { "frequency", 1, 0, 'f' },
|
cannam@95
|
132 { "crisp", 1, 0, 'c' },
|
cannam@95
|
133 { "crispness", 1, 0, 'c' },
|
cannam@95
|
134 { "debug", 1, 0, 'd' },
|
cannam@95
|
135 { "realtime", 0, 0, 'R' },
|
cannam@95
|
136 { "loose", 0, 0, 'L' },
|
cannam@95
|
137 { "precise", 0, 0, 'P' },
|
cannam@95
|
138 { "formant", 0, 0, 'F' },
|
cannam@95
|
139 { "no-threads", 0, 0, '0' },
|
cannam@95
|
140 { "no-transients", 0, 0, '1' },
|
cannam@95
|
141 { "no-lamination", 0, 0, '2' },
|
cannam@95
|
142 { "centre-focus", 0, 0, '7' },
|
cannam@95
|
143 { "window-long", 0, 0, '3' },
|
cannam@95
|
144 { "window-short", 0, 0, '4' },
|
cannam@95
|
145 { "bl-transients", 0, 0, '8' },
|
cannam@95
|
146 { "detector-perc", 0, 0, '5' },
|
cannam@95
|
147 { "detector-soft", 0, 0, '6' },
|
cannam@95
|
148 { "smoothing", 0, 0, '9' },
|
cannam@95
|
149 { "pitch-hq", 0, 0, '%' },
|
cannam@95
|
150 { "threads", 0, 0, '@' },
|
cannam@95
|
151 { "quiet", 0, 0, 'q' },
|
cannam@95
|
152 { "timemap", 1, 0, 'M' },
|
cannam@95
|
153 { 0, 0, 0, 0 }
|
cannam@95
|
154 };
|
cannam@95
|
155
|
cannam@95
|
156 c = getopt_long(argc, argv,
|
cannam@95
|
157 "t:p:d:RLPFc:f:T:D:qhVM:",
|
cannam@95
|
158 longOpts, &optionIndex);
|
cannam@95
|
159 if (c == -1) break;
|
cannam@95
|
160
|
cannam@95
|
161 switch (c) {
|
cannam@95
|
162 case 'h': help = true; break;
|
cannam@95
|
163 case 'V': version = true; break;
|
cannam@95
|
164 case 't': ratio *= atof(optarg); haveRatio = true; break;
|
cannam@95
|
165 case 'T': ratio *= tempo_convert(optarg); haveRatio = true; break;
|
cannam@95
|
166 case 'D': duration = atof(optarg); haveRatio = true; break;
|
cannam@95
|
167 case 'p': pitchshift = atof(optarg); haveRatio = true; break;
|
cannam@95
|
168 case 'f': frequencyshift = atof(optarg); haveRatio = true; break;
|
cannam@95
|
169 case 'd': debug = atoi(optarg); break;
|
cannam@95
|
170 case 'R': realtime = true; break;
|
cannam@95
|
171 case 'L': precise = false; break;
|
cannam@95
|
172 case 'P': precise = true; break;
|
cannam@95
|
173 case 'F': formant = true; break;
|
cannam@95
|
174 case '0': threading = 1; break;
|
cannam@95
|
175 case '@': threading = 2; break;
|
cannam@95
|
176 case '1': transients = NoTransients; crispchanged = true; break;
|
cannam@95
|
177 case '2': lamination = false; crispchanged = true; break;
|
cannam@95
|
178 case '3': longwin = true; crispchanged = true; break;
|
cannam@95
|
179 case '4': shortwin = true; crispchanged = true; break;
|
cannam@95
|
180 case '5': detector = PercussiveDetector; crispchanged = true; break;
|
cannam@95
|
181 case '6': detector = SoftDetector; crispchanged = true; break;
|
cannam@95
|
182 case '7': together = true; break;
|
cannam@95
|
183 case '8': transients = BandLimitedTransients; crispchanged = true; break;
|
cannam@95
|
184 case '9': smoothing = true; crispchanged = true; break;
|
cannam@95
|
185 case '%': hqpitch = true; break;
|
cannam@95
|
186 case 'c': crispness = atoi(optarg); break;
|
cannam@95
|
187 case 'q': quiet = true; break;
|
cannam@95
|
188 case 'M': mapfile = optarg; break;
|
cannam@95
|
189 default: help = true; break;
|
cannam@95
|
190 }
|
cannam@95
|
191 }
|
cannam@95
|
192
|
cannam@95
|
193 if (version) {
|
cannam@95
|
194 cerr << RUBBERBAND_VERSION << endl;
|
cannam@95
|
195 return 0;
|
cannam@95
|
196 }
|
cannam@95
|
197
|
cannam@95
|
198 if (help || !haveRatio || optind + 2 != argc) {
|
cannam@95
|
199 cerr << endl;
|
cannam@95
|
200 cerr << "Rubber Band" << endl;
|
cannam@95
|
201 cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl;
|
cannam@95
|
202 cerr << "Copyright 2007-2012 Particular Programs Ltd." << endl;
|
cannam@95
|
203 cerr << endl;
|
cannam@95
|
204 cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl;
|
cannam@95
|
205 cerr << endl;
|
cannam@95
|
206 cerr << "You must specify at least one of the following time and pitch ratio options." << endl;
|
cannam@95
|
207 cerr << endl;
|
cannam@95
|
208 cerr << " -t<X>, --time <X> Stretch to X times original duration, or" << endl;
|
cannam@95
|
209 cerr << " -T<X>, --tempo <X> Change tempo by multiple X (same as --time 1/X), or" << endl;
|
cannam@95
|
210 cerr << " -T<X>, --tempo <X>:<Y> Change tempo from X to Y (same as --time X/Y), or" << endl;
|
cannam@95
|
211 cerr << " -D<X>, --duration <X> Stretch or squash to make output file X seconds long" << endl;
|
cannam@95
|
212 cerr << endl;
|
cannam@95
|
213 cerr << " -p<X>, --pitch <X> Raise pitch by X semitones, or" << endl;
|
cannam@95
|
214 cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl;
|
cannam@95
|
215 cerr << endl;
|
cannam@95
|
216 cerr << " -M<F>, --timemap <F> Use file F as the source for key frame map" << endl;
|
cannam@95
|
217 cerr << endl;
|
cannam@95
|
218 cerr << "A map file consists of a series of lines each having two numbers separated" << endl;
|
cannam@95
|
219 cerr << "by a single space. These are source and target sample frame numbers for fixed" << endl;
|
cannam@95
|
220 cerr << "time points within the audio data, defining a varying stretch factor through" << endl;
|
cannam@95
|
221 cerr << "the audio. You must specify an overall stretch factor using e.g. -t as well." << endl;
|
cannam@95
|
222 cerr << endl;
|
cannam@95
|
223 cerr << "The following options provide a simple way to adjust the sound. See below" << endl;
|
cannam@95
|
224 cerr << "for more details." << endl;
|
cannam@95
|
225 cerr << endl;
|
cannam@95
|
226 cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5,6); default 5 (see below)" << endl;
|
cannam@95
|
227 cerr << " -F, --formant Enable formant preservation when pitch shifting" << endl;
|
cannam@95
|
228 cerr << endl;
|
cannam@95
|
229 cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl;
|
cannam@95
|
230 cerr << "These are mostly included for test purposes; the default settings and standard" << endl;
|
cannam@95
|
231 cerr << "crispness parameter are intended to provide the best sounding set of options" << endl;
|
cannam@95
|
232 cerr << "for most situations. The default is to use none of these options." << endl;
|
cannam@95
|
233 cerr << endl;
|
cannam@95
|
234 cerr << " -L, --loose Relax timing in hope of better transient preservation" << endl;
|
cannam@95
|
235 cerr << " -P, --precise Ignored: The opposite of -L, this is default from 1.6" << endl;
|
cannam@95
|
236 cerr << " -R, --realtime Select realtime mode (implies --no-threads)" << endl;
|
cannam@95
|
237 cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl;
|
cannam@95
|
238 cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl;
|
cannam@95
|
239 cerr << " --no-transients Disable phase resynchronisation at transients" << endl;
|
cannam@95
|
240 cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl;
|
cannam@95
|
241 cerr << " --no-lamination Disable phase lamination" << endl;
|
cannam@95
|
242 cerr << " --window-long Use longer processing window (actual size may vary)" << endl;
|
cannam@95
|
243 cerr << " --window-short Use shorter processing window" << endl;
|
cannam@95
|
244 cerr << " --smoothing Apply window presum and time-domain smoothing" << endl;
|
cannam@95
|
245 cerr << " --detector-perc Use percussive transient detector (as in pre-1.5)" << endl;
|
cannam@95
|
246 cerr << " --detector-soft Use soft transient detector" << endl;
|
cannam@95
|
247 cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl;
|
cannam@95
|
248 cerr << " --centre-focus Preserve focus of centre material in stereo" << endl;
|
cannam@95
|
249 cerr << " (at a cost in width and individual channel quality)" << endl;
|
cannam@95
|
250 cerr << endl;
|
cannam@95
|
251 cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
|
cannam@95
|
252 cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
|
cannam@95
|
253 cerr << " -q, --quiet Suppress progress output" << endl;
|
cannam@95
|
254 cerr << endl;
|
cannam@95
|
255 cerr << " -V, --version Show version number and exit" << endl;
|
cannam@95
|
256 cerr << " -h, --help Show this help" << endl;
|
cannam@95
|
257 cerr << endl;
|
cannam@95
|
258 cerr << "\"Crispness\" levels:" << endl;
|
cannam@95
|
259 cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl;
|
cannam@95
|
260 cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl;
|
cannam@95
|
261 cerr << " -c 2 equivalent to --no-transients --no-lamination" << endl;
|
cannam@95
|
262 cerr << " -c 3 equivalent to --no-transients" << endl;
|
cannam@95
|
263 cerr << " -c 4 equivalent to --bl-transients" << endl;
|
cannam@95
|
264 cerr << " -c 5 default processing options" << endl;
|
cannam@95
|
265 cerr << " -c 6 equivalent to --no-lamination --window-short (may be good for drums)" << endl;
|
cannam@95
|
266 cerr << endl;
|
cannam@95
|
267 return 2;
|
cannam@95
|
268 }
|
cannam@95
|
269
|
cannam@95
|
270 if (crispness >= 0 && crispchanged) {
|
cannam@95
|
271 cerr << "WARNING: Both crispness option and transients, lamination or window options" << endl;
|
cannam@95
|
272 cerr << " provided -- crispness will override these other options" << endl;
|
cannam@95
|
273 }
|
cannam@95
|
274
|
cannam@95
|
275 switch (crispness) {
|
cannam@95
|
276 case -1: crispness = 5; break;
|
cannam@95
|
277 case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
|
cannam@95
|
278 case 1: detector = SoftDetector; transients = Transients; lamination = false; longwin = true; shortwin = false; break;
|
cannam@95
|
279 case 2: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
|
cannam@95
|
280 case 3: detector = CompoundDetector; transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
|
cannam@95
|
281 case 4: detector = CompoundDetector; transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break;
|
cannam@95
|
282 case 5: detector = CompoundDetector; transients = Transients; lamination = true; longwin = false; shortwin = false; break;
|
cannam@95
|
283 case 6: detector = CompoundDetector; transients = Transients; lamination = false; longwin = false; shortwin = true; break;
|
cannam@95
|
284 };
|
cannam@95
|
285
|
cannam@95
|
286 if (!quiet) {
|
cannam@95
|
287 cerr << "Using crispness level: " << crispness << " (";
|
cannam@95
|
288 switch (crispness) {
|
cannam@95
|
289 case 0: cerr << "Mushy"; break;
|
cannam@95
|
290 case 1: cerr << "Piano"; break;
|
cannam@95
|
291 case 2: cerr << "Smooth"; break;
|
cannam@95
|
292 case 3: cerr << "Balanced multitimbral mixture"; break;
|
cannam@95
|
293 case 4: cerr << "Unpitched percussion with stable notes"; break;
|
cannam@95
|
294 case 5: cerr << "Crisp monophonic instrumental"; break;
|
cannam@95
|
295 case 6: cerr << "Unpitched solo percussion"; break;
|
cannam@95
|
296 }
|
cannam@95
|
297 cerr << ")" << endl;
|
cannam@95
|
298 }
|
cannam@95
|
299
|
cannam@95
|
300 std::map<size_t, size_t> mapping;
|
cannam@95
|
301
|
cannam@95
|
302 if (mapfile != "") {
|
cannam@95
|
303 std::ifstream ifile(mapfile.c_str());
|
cannam@95
|
304 if (!ifile.is_open()) {
|
cannam@95
|
305 cerr << "ERROR: Failed to open time map file \"" << mapfile << "\""
|
cannam@95
|
306 << endl;
|
cannam@95
|
307 return 1;
|
cannam@95
|
308 }
|
cannam@95
|
309 std::string line;
|
cannam@95
|
310 int lineno = 0;
|
cannam@95
|
311 while (!ifile.eof()) {
|
cannam@95
|
312 std::getline(ifile, line);
|
cannam@95
|
313 while (line.length() > 0 && line[0] == ' ') line = line.substr(1);
|
cannam@95
|
314 if (line == "") {
|
cannam@95
|
315 ++lineno;
|
cannam@95
|
316 continue;
|
cannam@95
|
317 }
|
cannam@95
|
318 std::string::size_type i = line.find_first_of(" ");
|
cannam@95
|
319 if (i == std::string::npos) {
|
cannam@95
|
320 cerr << "ERROR: Time map file \"" << mapfile
|
cannam@95
|
321 << "\" is malformed at line " << lineno << endl;
|
cannam@95
|
322 return 1;
|
cannam@95
|
323 }
|
cannam@95
|
324 size_t source = atoi(line.substr(0, i).c_str());
|
cannam@95
|
325 while (i < line.length() && line[i] == ' ') ++i;
|
cannam@95
|
326 size_t target = atoi(line.substr(i).c_str());
|
cannam@95
|
327 mapping[source] = target;
|
cannam@95
|
328 if (debug > 0) {
|
cannam@95
|
329 cerr << "adding mapping from " << source << " to " << target << endl;
|
cannam@95
|
330 }
|
cannam@95
|
331 ++lineno;
|
cannam@95
|
332 }
|
cannam@95
|
333 ifile.close();
|
cannam@95
|
334
|
cannam@95
|
335 if (!quiet) {
|
cannam@95
|
336 cerr << "Read " << mapping.size() << " line(s) from map file" << endl;
|
cannam@95
|
337 }
|
cannam@95
|
338 }
|
cannam@95
|
339
|
cannam@95
|
340 char *fileName = strdup(argv[optind++]);
|
cannam@95
|
341 char *fileNameOut = strdup(argv[optind++]);
|
cannam@95
|
342
|
cannam@95
|
343 SNDFILE *sndfile;
|
cannam@95
|
344 SNDFILE *sndfileOut;
|
cannam@95
|
345 SF_INFO sfinfo;
|
cannam@95
|
346 SF_INFO sfinfoOut;
|
cannam@95
|
347 memset(&sfinfo, 0, sizeof(SF_INFO));
|
cannam@95
|
348
|
cannam@95
|
349 sndfile = sf_open(fileName, SFM_READ, &sfinfo);
|
cannam@95
|
350 if (!sndfile) {
|
cannam@95
|
351 cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
|
cannam@95
|
352 << sf_strerror(sndfile) << endl;
|
cannam@95
|
353 return 1;
|
cannam@95
|
354 }
|
cannam@95
|
355
|
cannam@95
|
356 if (duration != 0.0) {
|
cannam@95
|
357 if (sfinfo.frames == 0 || sfinfo.samplerate == 0) {
|
cannam@95
|
358 cerr << "ERROR: File lacks frame count or sample rate in header, cannot use --duration" << endl;
|
cannam@95
|
359 return 1;
|
cannam@95
|
360 }
|
cannam@95
|
361 double induration = double(sfinfo.frames) / double(sfinfo.samplerate);
|
cannam@95
|
362 if (induration != 0.0) ratio = duration / induration;
|
cannam@95
|
363 }
|
cannam@95
|
364
|
cannam@95
|
365 sfinfoOut.channels = sfinfo.channels;
|
cannam@95
|
366 sfinfoOut.format = sfinfo.format;
|
cannam@95
|
367 sfinfoOut.frames = int(sfinfo.frames * ratio + 0.1);
|
cannam@95
|
368 sfinfoOut.samplerate = sfinfo.samplerate;
|
cannam@95
|
369 sfinfoOut.sections = sfinfo.sections;
|
cannam@95
|
370 sfinfoOut.seekable = sfinfo.seekable;
|
cannam@95
|
371
|
cannam@95
|
372 sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ;
|
cannam@95
|
373 if (!sndfileOut) {
|
cannam@95
|
374 cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
|
cannam@95
|
375 << sf_strerror(sndfileOut) << endl;
|
cannam@95
|
376 return 1;
|
cannam@95
|
377 }
|
cannam@95
|
378
|
cannam@95
|
379 int ibs = 1024;
|
cannam@95
|
380 size_t channels = sfinfo.channels;
|
cannam@95
|
381
|
cannam@95
|
382 RubberBandStretcher::Options options = 0;
|
cannam@95
|
383 if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
|
cannam@95
|
384 if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
|
cannam@95
|
385 if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
|
cannam@95
|
386 if (longwin) options |= RubberBandStretcher::OptionWindowLong;
|
cannam@95
|
387 if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
|
cannam@95
|
388 if (smoothing) options |= RubberBandStretcher::OptionSmoothingOn;
|
cannam@95
|
389 if (formant) options |= RubberBandStretcher::OptionFormantPreserved;
|
cannam@95
|
390 if (hqpitch) options |= RubberBandStretcher::OptionPitchHighQuality;
|
cannam@95
|
391 if (together) options |= RubberBandStretcher::OptionChannelsTogether;
|
cannam@95
|
392
|
cannam@95
|
393 switch (threading) {
|
cannam@95
|
394 case 0:
|
cannam@95
|
395 options |= RubberBandStretcher::OptionThreadingAuto;
|
cannam@95
|
396 break;
|
cannam@95
|
397 case 1:
|
cannam@95
|
398 options |= RubberBandStretcher::OptionThreadingNever;
|
cannam@95
|
399 break;
|
cannam@95
|
400 case 2:
|
cannam@95
|
401 options |= RubberBandStretcher::OptionThreadingAlways;
|
cannam@95
|
402 break;
|
cannam@95
|
403 }
|
cannam@95
|
404
|
cannam@95
|
405 switch (transients) {
|
cannam@95
|
406 case NoTransients:
|
cannam@95
|
407 options |= RubberBandStretcher::OptionTransientsSmooth;
|
cannam@95
|
408 break;
|
cannam@95
|
409 case BandLimitedTransients:
|
cannam@95
|
410 options |= RubberBandStretcher::OptionTransientsMixed;
|
cannam@95
|
411 break;
|
cannam@95
|
412 case Transients:
|
cannam@95
|
413 options |= RubberBandStretcher::OptionTransientsCrisp;
|
cannam@95
|
414 break;
|
cannam@95
|
415 }
|
cannam@95
|
416
|
cannam@95
|
417 switch (detector) {
|
cannam@95
|
418 case CompoundDetector:
|
cannam@95
|
419 options |= RubberBandStretcher::OptionDetectorCompound;
|
cannam@95
|
420 break;
|
cannam@95
|
421 case PercussiveDetector:
|
cannam@95
|
422 options |= RubberBandStretcher::OptionDetectorPercussive;
|
cannam@95
|
423 break;
|
cannam@95
|
424 case SoftDetector:
|
cannam@95
|
425 options |= RubberBandStretcher::OptionDetectorSoft;
|
cannam@95
|
426 break;
|
cannam@95
|
427 }
|
cannam@95
|
428
|
cannam@95
|
429 if (pitchshift != 0.0) {
|
cannam@95
|
430 frequencyshift *= pow(2.0, pitchshift / 12);
|
cannam@95
|
431 }
|
cannam@95
|
432
|
cannam@95
|
433 cerr << "Using time ratio " << ratio;
|
cannam@95
|
434 cerr << " and frequency ratio " << frequencyshift << endl;
|
cannam@95
|
435
|
cannam@95
|
436 #ifdef _WIN32
|
cannam@95
|
437 RubberBand::
|
cannam@95
|
438 #endif
|
cannam@95
|
439 timeval tv;
|
cannam@95
|
440 (void)gettimeofday(&tv, 0);
|
cannam@95
|
441
|
cannam@95
|
442 RubberBandStretcher::setDefaultDebugLevel(debug);
|
cannam@95
|
443
|
cannam@95
|
444 RubberBandStretcher ts(sfinfo.samplerate, channels, options,
|
cannam@95
|
445 ratio, frequencyshift);
|
cannam@95
|
446
|
cannam@95
|
447 ts.setExpectedInputDuration(sfinfo.frames);
|
cannam@95
|
448
|
cannam@95
|
449 float *fbuf = new float[channels * ibs];
|
cannam@95
|
450 float **ibuf = new float *[channels];
|
cannam@95
|
451 for (size_t i = 0; i < channels; ++i) ibuf[i] = new float[ibs];
|
cannam@95
|
452
|
cannam@95
|
453 int frame = 0;
|
cannam@95
|
454 int percent = 0;
|
cannam@95
|
455
|
cannam@95
|
456 sf_seek(sndfile, 0, SEEK_SET);
|
cannam@95
|
457
|
cannam@95
|
458 if (!realtime) {
|
cannam@95
|
459
|
cannam@95
|
460 if (!quiet) {
|
cannam@95
|
461 cerr << "Pass 1: Studying..." << endl;
|
cannam@95
|
462 }
|
cannam@95
|
463
|
cannam@95
|
464 while (frame < sfinfo.frames) {
|
cannam@95
|
465
|
cannam@95
|
466 int count = -1;
|
cannam@95
|
467
|
cannam@95
|
468 if ((count = sf_readf_float(sndfile, fbuf, ibs)) <= 0) break;
|
cannam@95
|
469
|
cannam@95
|
470 for (size_t c = 0; c < channels; ++c) {
|
cannam@95
|
471 for (int i = 0; i < count; ++i) {
|
cannam@95
|
472 float value = fbuf[i * channels + c];
|
cannam@95
|
473 ibuf[c][i] = value;
|
cannam@95
|
474 }
|
cannam@95
|
475 }
|
cannam@95
|
476
|
cannam@95
|
477 bool final = (frame + ibs >= sfinfo.frames);
|
cannam@95
|
478
|
cannam@95
|
479 ts.study(ibuf, count, final);
|
cannam@95
|
480
|
cannam@95
|
481 int p = int((double(frame) * 100.0) / sfinfo.frames);
|
cannam@95
|
482 if (p > percent || frame == 0) {
|
cannam@95
|
483 percent = p;
|
cannam@95
|
484 if (!quiet) {
|
cannam@95
|
485 cerr << "\r" << percent << "% ";
|
cannam@95
|
486 }
|
cannam@95
|
487 }
|
cannam@95
|
488
|
cannam@95
|
489 frame += ibs;
|
cannam@95
|
490 }
|
cannam@95
|
491
|
cannam@95
|
492 if (!quiet) {
|
cannam@95
|
493 cerr << "\rCalculating profile..." << endl;
|
cannam@95
|
494 }
|
cannam@95
|
495
|
cannam@95
|
496 sf_seek(sndfile, 0, SEEK_SET);
|
cannam@95
|
497 }
|
cannam@95
|
498
|
cannam@95
|
499 frame = 0;
|
cannam@95
|
500 percent = 0;
|
cannam@95
|
501
|
cannam@95
|
502 if (!mapping.empty()) {
|
cannam@95
|
503 ts.setKeyFrameMap(mapping);
|
cannam@95
|
504 }
|
cannam@95
|
505
|
cannam@95
|
506 size_t countIn = 0, countOut = 0;
|
cannam@95
|
507
|
cannam@95
|
508 while (frame < sfinfo.frames) {
|
cannam@95
|
509
|
cannam@95
|
510 int count = -1;
|
cannam@95
|
511
|
cannam@95
|
512 if ((count = sf_readf_float(sndfile, fbuf, ibs)) < 0) break;
|
cannam@95
|
513
|
cannam@95
|
514 countIn += count;
|
cannam@95
|
515
|
cannam@95
|
516 for (size_t c = 0; c < channels; ++c) {
|
cannam@95
|
517 for (int i = 0; i < count; ++i) {
|
cannam@95
|
518 float value = fbuf[i * channels + c];
|
cannam@95
|
519 ibuf[c][i] = value;
|
cannam@95
|
520 }
|
cannam@95
|
521 }
|
cannam@95
|
522
|
cannam@95
|
523 bool final = (frame + ibs >= sfinfo.frames);
|
cannam@95
|
524
|
cannam@95
|
525 if (debug > 2) {
|
cannam@95
|
526 cerr << "count = " << count << ", ibs = " << ibs << ", frame = " << frame << ", frames = " << sfinfo.frames << ", final = " << final << endl;
|
cannam@95
|
527 }
|
cannam@95
|
528
|
cannam@95
|
529 ts.process(ibuf, count, final);
|
cannam@95
|
530
|
cannam@95
|
531 int avail = ts.available();
|
cannam@95
|
532 if (debug > 1) cerr << "available = " << avail << endl;
|
cannam@95
|
533
|
cannam@95
|
534 if (avail > 0) {
|
cannam@95
|
535 float **obf = new float *[channels];
|
cannam@95
|
536 for (size_t i = 0; i < channels; ++i) {
|
cannam@95
|
537 obf[i] = new float[avail];
|
cannam@95
|
538 }
|
cannam@95
|
539 ts.retrieve(obf, avail);
|
cannam@95
|
540 countOut += avail;
|
cannam@95
|
541 float *fobf = new float[channels * avail];
|
cannam@95
|
542 for (size_t c = 0; c < channels; ++c) {
|
cannam@95
|
543 for (int i = 0; i < avail; ++i) {
|
cannam@95
|
544 float value = obf[c][i];
|
cannam@95
|
545 if (value > 1.f) value = 1.f;
|
cannam@95
|
546 if (value < -1.f) value = -1.f;
|
cannam@95
|
547 fobf[i * channels + c] = value;
|
cannam@95
|
548 }
|
cannam@95
|
549 }
|
cannam@95
|
550 // cout << "fobf mean: ";
|
cannam@95
|
551 // double d = 0;
|
cannam@95
|
552 // for (int i = 0; i < avail; ++i) {
|
cannam@95
|
553 // d += fobf[i];
|
cannam@95
|
554 // }
|
cannam@95
|
555 // d /= avail;
|
cannam@95
|
556 // cout << d << endl;
|
cannam@95
|
557 sf_writef_float(sndfileOut, fobf, avail);
|
cannam@95
|
558 delete[] fobf;
|
cannam@95
|
559 for (size_t i = 0; i < channels; ++i) {
|
cannam@95
|
560 delete[] obf[i];
|
cannam@95
|
561 }
|
cannam@95
|
562 delete[] obf;
|
cannam@95
|
563 }
|
cannam@95
|
564
|
cannam@95
|
565 if (frame == 0 && !realtime && !quiet) {
|
cannam@95
|
566 cerr << "Pass 2: Processing..." << endl;
|
cannam@95
|
567 }
|
cannam@95
|
568
|
cannam@95
|
569 int p = int((double(frame) * 100.0) / sfinfo.frames);
|
cannam@95
|
570 if (p > percent || frame == 0) {
|
cannam@95
|
571 percent = p;
|
cannam@95
|
572 if (!quiet) {
|
cannam@95
|
573 cerr << "\r" << percent << "% ";
|
cannam@95
|
574 }
|
cannam@95
|
575 }
|
cannam@95
|
576
|
cannam@95
|
577 frame += ibs;
|
cannam@95
|
578 }
|
cannam@95
|
579
|
cannam@95
|
580 if (!quiet) {
|
cannam@95
|
581 cerr << "\r " << endl;
|
cannam@95
|
582 }
|
cannam@95
|
583 int avail;
|
cannam@95
|
584
|
cannam@95
|
585 while ((avail = ts.available()) >= 0) {
|
cannam@95
|
586
|
cannam@95
|
587 if (debug > 1) {
|
cannam@95
|
588 cerr << "(completing) available = " << avail << endl;
|
cannam@95
|
589 }
|
cannam@95
|
590
|
cannam@95
|
591 if (avail > 0) {
|
cannam@95
|
592 float **obf = new float *[channels];
|
cannam@95
|
593 for (size_t i = 0; i < channels; ++i) {
|
cannam@95
|
594 obf[i] = new float[avail];
|
cannam@95
|
595 }
|
cannam@95
|
596 ts.retrieve(obf, avail);
|
cannam@95
|
597 countOut += avail;
|
cannam@95
|
598 float *fobf = new float[channels * avail];
|
cannam@95
|
599 for (size_t c = 0; c < channels; ++c) {
|
cannam@95
|
600 for (int i = 0; i < avail; ++i) {
|
cannam@95
|
601 float value = obf[c][i];
|
cannam@95
|
602 if (value > 1.f) value = 1.f;
|
cannam@95
|
603 if (value < -1.f) value = -1.f;
|
cannam@95
|
604 fobf[i * channels + c] = value;
|
cannam@95
|
605 }
|
cannam@95
|
606 }
|
cannam@95
|
607
|
cannam@95
|
608 sf_writef_float(sndfileOut, fobf, avail);
|
cannam@95
|
609 delete[] fobf;
|
cannam@95
|
610 for (size_t i = 0; i < channels; ++i) {
|
cannam@95
|
611 delete[] obf[i];
|
cannam@95
|
612 }
|
cannam@95
|
613 delete[] obf;
|
cannam@95
|
614 } else {
|
cannam@95
|
615 usleep(10000);
|
cannam@95
|
616 }
|
cannam@95
|
617 }
|
cannam@95
|
618
|
cannam@95
|
619 sf_close(sndfile);
|
cannam@95
|
620 sf_close(sndfileOut);
|
cannam@95
|
621
|
cannam@95
|
622 if (!quiet) {
|
cannam@95
|
623
|
cannam@95
|
624 cerr << "in: " << countIn << ", out: " << countOut << ", ratio: " << float(countOut)/float(countIn) << ", ideal output: " << lrint(countIn * ratio) << ", error: " << abs(lrint(countIn * ratio) - int(countOut)) << endl;
|
cannam@95
|
625
|
cannam@95
|
626 #ifdef _WIN32
|
cannam@95
|
627 RubberBand::
|
cannam@95
|
628 #endif
|
cannam@95
|
629 timeval etv;
|
cannam@95
|
630 (void)gettimeofday(&etv, 0);
|
cannam@95
|
631
|
cannam@95
|
632 etv.tv_sec -= tv.tv_sec;
|
cannam@95
|
633 if (etv.tv_usec < tv.tv_usec) {
|
cannam@95
|
634 etv.tv_usec += 1000000;
|
cannam@95
|
635 etv.tv_sec -= 1;
|
cannam@95
|
636 }
|
cannam@95
|
637 etv.tv_usec -= tv.tv_usec;
|
cannam@95
|
638
|
cannam@95
|
639 double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
|
cannam@95
|
640 cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl;
|
cannam@95
|
641 }
|
cannam@95
|
642
|
cannam@95
|
643 RubberBand::Profiler::dump();
|
cannam@95
|
644
|
cannam@95
|
645 return 0;
|
cannam@95
|
646 }
|
cannam@95
|
647
|
cannam@95
|
648
|