1 ////////////////////////////////////////////////////////////////////////////////
2 ///
3 /// A class for parsing the 'soundstretch' application command line parameters
4 ///
5 /// Author : Copyright (c) Olli Parviainen
6 /// Author e-mail : oparviai 'at' iki.fi
7 /// SoundTouch WWW: http://www.surina.net/soundtouch
8 ///
9 ////////////////////////////////////////////////////////////////////////////////
10 //
11 // Last changed : $Date: 2011-09-02 21:56:11 +0300 (Fri, 02 Sep 2011) $
12 // File revision : $Revision: 4 $
13 //
14 // $Id: RunParameters.cpp 131 2011-09-02 18:56:11Z oparviai $
15 //
16 ////////////////////////////////////////////////////////////////////////////////
17 //
18 // License :
19 //
20 // SoundTouch audio processing library
21 // Copyright (c) Olli Parviainen
22 //
23 // This library is free software; you can redistribute it and/or
24 // modify it under the terms of the GNU Lesser General Public
25 // License as published by the Free Software Foundation; either
26 // version 2.1 of the License, or (at your option) any later version.
27 //
28 // This library is distributed in the hope that it will be useful,
29 // but WITHOUT ANY WARRANTY; without even the implied warranty of
30 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31 // Lesser General Public License for more details.
32 //
33 // You should have received a copy of the GNU Lesser General Public
34 // License along with this library; if not, write to the Free Software
35 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 //
37 ////////////////////////////////////////////////////////////////////////////////
38
39 #include <string>
40 #include <stdlib.h>
41
42 #include "RunParameters.h"
43
44 using namespace std;
45
46 // Program usage instructions
47
48 static const char licenseText[] =
49 " LICENSE:\n"
50 " ========\n"
51 " \n"
52 " SoundTouch sound processing library\n"
53 " Copyright (c) Olli Parviainen\n"
54 " \n"
55 " This library is free software; you can redistribute it and/or\n"
56 " modify it under the terms of the GNU Lesser General Public\n"
57 " License version 2.1 as published by the Free Software Foundation.\n"
58 " \n"
59 " This library is distributed in the hope that it will be useful,\n"
60 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
61 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
62 " Lesser General Public License for more details.\n"
63 " \n"
64 " You should have received a copy of the GNU Lesser General Public\n"
65 " License along with this library; if not, write to the Free Software\n"
66 " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
67 " \n"
68 "This application is distributed with full source codes; however, if you\n"
69 "didn't receive them, please visit the author's homepage (see the link above).";
70
71 static const char whatText[] =
72 "This application processes WAV audio files by modifying the sound tempo,\n"
73 "pitch and playback rate properties independently from each other.\n"
74 "\n";
75
76 static const char usage[] =
77 "Usage :\n"
78 " soundstretch infilename outfilename [switches]\n"
79 "\n"
80 "To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
81 "\n"
82 "Available switches are:\n"
83 " -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
84 " -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
85 " -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
86 " -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
87 " If '=n' is omitted, just detects the BPM rate.\n"
88 " -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
89 " -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
90 " -speech : Tune algorithm for speech processing (default is for music)\n"
91 " -license : Display the program license text (LGPL)\n";
92
93
94 // Converts a char into lower case
_toLowerCase(int c)95 static int _toLowerCase(int c)
96 {
97 if (c >= 'A' && c <= 'Z')
98 {
99 c += 'a' - 'A';
100 }
101 return c;
102 }
103
104
105 // Constructor
RunParameters(const int nParams,const char * const paramStr[])106 RunParameters::RunParameters(const int nParams, const char * const paramStr[])
107 {
108 int i;
109 int nFirstParam;
110
111 if (nParams < 3)
112 {
113 // Too few parameters
114 if (nParams > 1 && paramStr[1][0] == '-' &&
115 _toLowerCase(paramStr[1][1]) == 'l')
116 {
117 // '-license' switch
118 throwLicense();
119 }
120 string msg = whatText;
121 msg += usage;
122 ST_THROW_RT_ERROR(msg.c_str());
123 }
124
125 inFileName = NULL;
126 outFileName = NULL;
127 tempoDelta = 0;
128 pitchDelta = 0;
129 rateDelta = 0;
130 quick = 0;
131 noAntiAlias = 0;
132 goalBPM = 0;
133 speech = FALSE;
134 detectBPM = FALSE;
135
136 // Get input & output file names
137 inFileName = (char*)paramStr[1];
138 outFileName = (char*)paramStr[2];
139
140 if (outFileName[0] == '-')
141 {
142 // no outputfile name was given but parameters
143 outFileName = NULL;
144 nFirstParam = 2;
145 }
146 else
147 {
148 nFirstParam = 3;
149 }
150
151 // parse switch parameters
152 for (i = nFirstParam; i < nParams; i ++)
153 {
154 parseSwitchParam(paramStr[i]);
155 }
156
157 checkLimits();
158 }
159
160
161
162 // Checks parameter limits
checkLimits()163 void RunParameters::checkLimits()
164 {
165 if (tempoDelta < -95.0f)
166 {
167 tempoDelta = -95.0f;
168 }
169 else if (tempoDelta > 5000.0f)
170 {
171 tempoDelta = 5000.0f;
172 }
173
174 if (pitchDelta < -60.0f)
175 {
176 pitchDelta = -60.0f;
177 }
178 else if (pitchDelta > 60.0f)
179 {
180 pitchDelta = 60.0f;
181 }
182
183 if (rateDelta < -95.0f)
184 {
185 rateDelta = -95.0f;
186 }
187 else if (rateDelta > 5000.0f)
188 {
189 rateDelta = 5000.0f;
190 }
191 }
192
193
194
195 // Unknown switch parameter -- throws an exception with an error message
throwIllegalParamExp(const string & str) const196 void RunParameters::throwIllegalParamExp(const string &str) const
197 {
198 string msg = "ERROR : Illegal parameter \"";
199 msg += str;
200 msg += "\".\n\n";
201 msg += usage;
202 ST_THROW_RT_ERROR(msg.c_str());
203 }
204
205
206
throwLicense() const207 void RunParameters::throwLicense() const
208 {
209 ST_THROW_RT_ERROR(licenseText);
210 }
211
212
parseSwitchValue(const string & str) const213 float RunParameters::parseSwitchValue(const string &str) const
214 {
215 int pos;
216
217 pos = (int)str.find_first_of('=');
218 if (pos < 0)
219 {
220 // '=' missing
221 throwIllegalParamExp(str);
222 }
223
224 // Read numerical parameter value after '='
225 return (float)atof(str.substr(pos + 1).c_str());
226 }
227
228
229 // Interprets a single switch parameter string of format "-switch=xx"
230 // Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
231 // switch values into 'params' structure.
parseSwitchParam(const string & str)232 void RunParameters::parseSwitchParam(const string &str)
233 {
234 int upS;
235
236 if (str[0] != '-')
237 {
238 // leading hyphen missing => not a valid parameter
239 throwIllegalParamExp(str);
240 }
241
242 // Take the first character of switch name & change to lower case
243 upS = _toLowerCase(str[1]);
244
245 // interpret the switch name & operate accordingly
246 switch (upS)
247 {
248 case 't' :
249 // switch '-tempo=xx'
250 tempoDelta = parseSwitchValue(str);
251 break;
252
253 case 'p' :
254 // switch '-pitch=xx'
255 pitchDelta = parseSwitchValue(str);
256 break;
257
258 case 'r' :
259 // switch '-rate=xx'
260 rateDelta = parseSwitchValue(str);
261 break;
262
263 case 'b' :
264 // switch '-bpm=xx'
265 detectBPM = TRUE;
266 try
267 {
268 goalBPM = parseSwitchValue(str);
269 }
270 catch (const runtime_error)
271 {
272 // illegal or missing bpm value => just calculate bpm
273 goalBPM = 0;
274 }
275 break;
276
277 case 'q' :
278 // switch '-quick'
279 quick = 1;
280 break;
281
282 case 'n' :
283 // switch '-naa'
284 noAntiAlias = 1;
285 break;
286
287 case 'l' :
288 // switch '-license'
289 throwLicense();
290 break;
291
292 case 's' :
293 // switch '-speech'
294 speech = TRUE;
295 break;
296
297 default:
298 // unknown switch
299 throwIllegalParamExp(str);
300 }
301 }
302