1 /*
2  *      Command line parsing related functions
3  *
4  *      Copyright (c) 1999 Mark Taylor
5  *                    2000-2012 Robert Hegemann
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 /* $Id: parse.c,v 1.292.2.2 2012/02/07 13:40:37 robert Exp $ */
24 
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <assert.h>
30 #include <ctype.h>
31 
32 #ifdef STDC_HEADERS
33 # include <stdio.h>
34 # include <stdlib.h>
35 # include <string.h>
36 #else
37 # ifndef HAVE_STRCHR
38 #  define strchr index
39 #  define strrchr rindex
40 # endif
41 char   *strchr(), *strrchr();
42 # ifndef HAVE_MEMCPY
43 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
44 #  define memmove(d, s, n) bcopy ((s), (d), (n))
45 # endif
46 #endif
47 
48 
49 #ifdef HAVE_LIMITS_H
50 # include <limits.h>
51 #endif
52 
53 #include "lame.h"
54 
55 #include "parse.h"
56 #include "main.h"
57 #include "get_audio.h"
58 #include "version.h"
59 #include "console.h"
60 
61 #undef dimension_of
62 #define dimension_of(array) (sizeof(array)/sizeof(array[0]))
63 
64 #ifdef WITH_DMALLOC
65 #include <dmalloc.h>
66 #endif
67 
68 
69 #ifdef HAVE_ICONV
70 #include <iconv.h>
71 #include <errno.h>
72 #endif
73 
74 #if defined _ALLOW_INTERNAL_OPTIONS
75 #define INTERNAL_OPTS 1
76 #else
77 #define INTERNAL_OPTS 0
78 #endif
79 
80 #if (INTERNAL_OPTS!=0)
81 #include "set_get.h"
82 #define DEV_HELP(a) a
83 #else
84 #define DEV_HELP(a)
85 #endif
86 
87 static int const lame_alpha_version_enabled = LAME_ALPHA_VERSION;
88 static int const internal_opts_enabled = INTERNAL_OPTS;
89 
90 /* GLOBAL VARIABLES.  set by parse_args() */
91 /* we need to clean this up */
92 
93 ReaderConfig global_reader = { sf_unknown, 0, 0, 0 };
94 WriterConfig global_writer = { 0 };
95 
96 UiConfig global_ui_config = {0,0,0,0};
97 
98 DecoderConfig global_decoder;
99 
100 RawPCMConfig global_raw_pcm =
101 { /* in_bitwidth */ 16
102 , /* in_signed   */ -1
103 , /* in_endian   */ ByteOrderLittleEndian
104 };
105 
106 
107 
108 /* possible text encodings */
109 typedef enum TextEncoding
110 { TENC_RAW     /* bytes will be stored as-is into ID3 tags, which are Latin1 per definition */
111 , TENC_LATIN1  /* text will be converted from local encoding to Latin1, as ID3 needs it */
112 , TENC_UTF16   /* text will be converted from local encoding to Unicode, as ID3v2 wants it */
113 } TextEncoding;
114 
115 #ifdef HAVE_ICONV
116 #define ID3TAGS_EXTENDED
117 /* search for Zero termination in multi-byte strings */
118 static size_t
strlenMultiByte(char const * str,size_t w)119 strlenMultiByte(char const* str, size_t w)
120 {
121     size_t n = 0;
122     if (str != 0) {
123         size_t i, x = 0;
124         for (n = 0; ; ++n) {
125             x = 0;
126             for (i = 0; i < w; ++i) {
127                 x += *str++ == 0 ? 1 : 0;
128             }
129             if (x == w) {
130                 break;
131             }
132         }
133     }
134     return n;
135 }
136 
137 
138 static size_t
currCharCodeSize(void)139 currCharCodeSize(void)
140 {
141     size_t n = 1;
142     char dst[32];
143     char* src = "A";
144     char* env_lang = getenv("LANG");
145     char* xxx_code = env_lang == NULL ? NULL : strrchr(env_lang, '.');
146     char* cur_code = xxx_code == NULL ? "" : xxx_code+1;
147     iconv_t xiconv = iconv_open(cur_code, "ISO_8859-1");
148     if (xiconv != (iconv_t)-1) {
149         for (n = 0; n < 32; ++n) {
150             char* i_ptr = src;
151             char* o_ptr = dst;
152             size_t srcln = 1;
153             size_t avail = n;
154             size_t rc = iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
155             if (rc != (size_t)-1) {
156                 break;
157             }
158         }
159         iconv_close(xiconv);
160     }
161     return n;
162 }
163 
164 #if 0
165 static
166 char* fromLatin1( char* src )
167 {
168     char* dst = 0;
169     if (src != 0) {
170         size_t const l = strlen(src);
171         size_t const n = l*4;
172         dst = calloc(n+4, 4);
173         if (dst != 0) {
174             char* env_lang = getenv("LANG");
175             char* xxx_code = env_lang == NULL ? NULL : strrchr(env_lang, '.');
176             char* cur_code = xxx_code == NULL ? "" : xxx_code+1;
177             iconv_t xiconv = iconv_open(cur_code, "ISO_8859-1");
178             if (xiconv != (iconv_t)-1) {
179                 char* i_ptr = src;
180                 char* o_ptr = dst;
181                 size_t srcln = l;
182                 size_t avail = n;
183                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
184                 iconv_close(xiconv);
185             }
186         }
187     }
188     return dst;
189 }
190 
191 static
192 char* fromUtf16( char* src )
193 {
194     char* dst = 0;
195     if (src != 0) {
196         size_t const l = strlenMultiByte(src, 2);
197         size_t const n = l*4;
198         dst = calloc(n+4, 4);
199         if (dst != 0) {
200             char* env_lang = getenv("LANG");
201             char* xxx_code = env_lang == NULL ? NULL : strrchr(env_lang, '.');
202             char* cur_code = xxx_code == NULL ? "" : xxx_code+1;
203             iconv_t xiconv = iconv_open(cur_code, "UTF-16LE");
204             if (xiconv != (iconv_t)-1) {
205                 char* i_ptr = (char*)src;
206                 char* o_ptr = dst;
207                 size_t srcln = l*2;
208                 size_t avail = n;
209                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
210                 iconv_close(xiconv);
211             }
212         }
213     }
214     return dst;
215 }
216 #endif
217 
218 static
toLatin1(char * src)219 char* toLatin1( char* src )
220 {
221     size_t w = currCharCodeSize();
222     char* dst = 0;
223     if (src != 0) {
224         size_t const l = strlenMultiByte(src, w);
225         size_t const n = l*4;
226         dst = calloc(n+4, 4);
227         if (dst != 0) {
228             char* env_lang = getenv("LANG");
229             char* xxx_code = env_lang == NULL ? NULL : strrchr(env_lang, '.');
230             char* cur_code = xxx_code == NULL ? "" : xxx_code+1;
231             iconv_t xiconv = iconv_open("ISO_8859-1//TRANSLIT", cur_code);
232             if (xiconv != (iconv_t)-1) {
233                 char* i_ptr = (char*)src;
234                 char* o_ptr = dst;
235                 size_t srcln = l*w;
236                 size_t avail = n;
237                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
238                 iconv_close(xiconv);
239             }
240         }
241     }
242     return dst;
243 }
244 
245 
246 static
toUtf16(char * src)247 char* toUtf16( char* src )
248 {
249     size_t w = currCharCodeSize();
250     char* dst = 0;
251     if (src != 0) {
252         size_t const l = strlenMultiByte(src, w);
253         size_t const n = (l+1)*4;
254         dst = calloc(n+4, 4);
255         if (dst != 0) {
256             char* env_lang = getenv("LANG");
257             char* xxx_code = env_lang == NULL ? NULL : strrchr(env_lang, '.');
258             char* cur_code = xxx_code == NULL ? "" : xxx_code+1;
259             iconv_t xiconv = iconv_open("UTF-16LE//TRANSLIT", cur_code);
260             dst[0] = 0xff;
261             dst[1] = 0xfe;
262             if (xiconv != (iconv_t)-1) {
263                 char* i_ptr = (char*)src;
264                 char* o_ptr = &dst[2];
265                 size_t srcln = l*w;
266                 size_t avail = n;
267                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
268                 iconv_close(xiconv);
269             }
270         }
271     }
272     return dst;
273 }
274 #endif
275 
276 #if defined( _WIN32 ) && !defined(__MINGW32__)
277 #define ID3TAGS_EXTENDED
278 
toLatin1(char const * s)279 char* toLatin1(char const* s)
280 {
281     return utf8ToLatin1(s);
282 }
283 
toUtf16(char const * s)284 unsigned short* toUtf16(char const* s)
285 {
286     return utf8ToUtf16(s);
287 }
288 #endif
289 
290 
291 static int
set_id3v2tag(lame_global_flags * gfp,int type,unsigned short const * str)292 set_id3v2tag(lame_global_flags* gfp, int type, unsigned short const* str)
293 {
294     switch (type)
295     {
296         case 'a': return id3tag_set_textinfo_utf16(gfp, "TPE1", str);
297         case 't': return id3tag_set_textinfo_utf16(gfp, "TIT2", str);
298         case 'l': return id3tag_set_textinfo_utf16(gfp, "TALB", str);
299         case 'g': return id3tag_set_textinfo_utf16(gfp, "TCON", str);
300         case 'c': return id3tag_set_comment_utf16(gfp, 0, 0, str);
301         case 'n': return id3tag_set_textinfo_utf16(gfp, "TRCK", str);
302         case 'y': return id3tag_set_textinfo_utf16(gfp, "TYER", str);
303         case 'v': return id3tag_set_fieldvalue_utf16(gfp, str);
304     }
305     return 0;
306 }
307 
308 
309 static int
set_id3tag(lame_global_flags * gfp,int type,char const * str)310 set_id3tag(lame_global_flags* gfp, int type, char const* str)
311 {
312     switch (type)
313     {
314         case 'a': return id3tag_set_artist(gfp, str), 0;
315         case 't': return id3tag_set_title(gfp, str), 0;
316         case 'l': return id3tag_set_album(gfp, str), 0;
317         case 'g': return id3tag_set_genre(gfp, str);
318         case 'c': return id3tag_set_comment(gfp, str), 0;
319         case 'n': return id3tag_set_track(gfp, str);
320         case 'y': return id3tag_set_year(gfp, str), 0;
321         case 'v': return id3tag_set_fieldvalue(gfp, str);
322     }
323     return 0;
324 }
325 
326 static int
id3_tag(lame_global_flags * gfp,int type,TextEncoding enc,char * str)327 id3_tag(lame_global_flags* gfp, int type, TextEncoding enc, char* str)
328 {
329     void* x = 0;
330     int result;
331     if (enc == TENC_UTF16 && type != 'v' ) {
332         id3_tag(gfp, type, TENC_LATIN1, str); /* for id3v1 */
333     }
334     switch (enc)
335     {
336         default:
337 #ifdef ID3TAGS_EXTENDED
338         case TENC_LATIN1: x = toLatin1(str); break;
339         case TENC_UTF16:  x = toUtf16(str);   break;
340 #else
341         case TENC_RAW:    x = strdup(str);   break;
342 #endif
343     }
344     switch (enc)
345     {
346         default:
347 #ifdef ID3TAGS_EXTENDED
348         case TENC_LATIN1: result = set_id3tag(gfp, type, x);   break;
349         case TENC_UTF16:  result = set_id3v2tag(gfp, type, x); break;
350 #else
351         case TENC_RAW:    result = set_id3tag(gfp, type, x);   break;
352 #endif
353     }
354     free(x);
355     return result;
356 }
357 
358 
359 
360 
361 /************************************************************************
362 *
363 * license
364 *
365 * PURPOSE:  Writes version and license to the file specified by fp
366 *
367 ************************************************************************/
368 
369 static int
lame_version_print(FILE * const fp)370 lame_version_print(FILE * const fp)
371 {
372     const char *b = get_lame_os_bitness();
373     const char *v = get_lame_version();
374     const char *u = get_lame_url();
375     const size_t lenb = strlen(b);
376     const size_t lenv = strlen(v);
377     const size_t lenu = strlen(u);
378     const size_t lw = 80;       /* line width of terminal in characters */
379     const size_t sw = 16;       /* static width of text */
380 
381     if (lw >= lenb + lenv + lenu + sw || lw < lenu + 2)
382         /* text fits in 80 chars per line, or line even too small for url */
383         if (lenb > 0)
384             fprintf(fp, "LAME %s version %s (%s)\n\n", b, v, u);
385         else
386             fprintf(fp, "LAME version %s (%s)\n\n", v, u);
387     else {
388         int const n_white_spaces = ((lenu+2) > lw ? 0 : lw-2-lenu);
389         /* text too long, wrap url into next line, right aligned */
390         if (lenb > 0)
391             fprintf(fp, "LAME %s version %s\n%*s(%s)\n\n", b, v, n_white_spaces, "", u);
392         else
393             fprintf(fp, "LAME version %s\n%*s(%s)\n\n", v, n_white_spaces, "", u);
394     }
395     if (lame_alpha_version_enabled)
396         fprintf(fp, "warning: alpha versions should be used for testing only\n\n");
397 
398 
399     return 0;
400 }
401 
402 static int
print_license(FILE * const fp)403 print_license(FILE * const fp)
404 {                       /* print version & license */
405     lame_version_print(fp);
406     fprintf(fp,
407             "Copyright (c) 1999-2011 by The LAME Project\n"
408             "Copyright (c) 1999,2000,2001 by Mark Taylor\n"
409             "Copyright (c) 1998 by Michael Cheng\n"
410             "Copyright (c) 1995,1996,1997 by Michael Hipp: mpglib\n" "\n");
411     fprintf(fp,
412             "This library is free software; you can redistribute it and/or\n"
413             "modify it under the terms of the GNU Library General Public\n"
414             "License as published by the Free Software Foundation; either\n"
415             "version 2 of the License, or (at your option) any later version.\n"
416             "\n"
417             "This library is distributed in the hope that it will be useful,\n"
418             "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
419             "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
420             "Library General Public License for more details.\n"
421             "\n"
422             "You should have received a copy of the GNU Library General Public\n"
423             "License along with this program. If not, see\n"
424             "<http://www.gnu.org/licenses/>.\n");
425     return 0;
426 }
427 
428 
429 /************************************************************************
430 *
431 * usage
432 *
433 * PURPOSE:  Writes command line syntax to the file specified by fp
434 *
435 ************************************************************************/
436 
437 int
usage(FILE * const fp,const char * ProgramName)438 usage(FILE * const fp, const char *ProgramName)
439 {                       /* print general syntax */
440     lame_version_print(fp);
441     fprintf(fp,
442             "usage: %s [options] <infile> [outfile]\n"
443             "\n"
444             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
445             "\n"
446             "Try:\n"
447             "     \"%s --help\"           for general usage information\n"
448             " or:\n"
449             "     \"%s --preset help\"    for information on suggested predefined settings\n"
450             " or:\n"
451             "     \"%s --longhelp\"\n"
452             "  or \"%s -?\"              for a complete options list\n\n",
453             ProgramName, ProgramName, ProgramName, ProgramName, ProgramName);
454     return 0;
455 }
456 
457 
458 /************************************************************************
459 *
460 * usage
461 *
462 * PURPOSE:  Writes command line syntax to the file specified by fp
463 *           but only the most important ones, to fit on a vt100 terminal
464 *
465 ************************************************************************/
466 
467 int
short_help(const lame_global_flags * gfp,FILE * const fp,const char * ProgramName)468 short_help(const lame_global_flags * gfp, FILE * const fp, const char *ProgramName)
469 {                       /* print short syntax help */
470     lame_version_print(fp);
471     fprintf(fp,
472             "usage: %s [options] <infile> [outfile]\n"
473             "\n"
474             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
475             "\n" "RECOMMENDED:\n" "    lame -V2 input.wav output.mp3\n" "\n", ProgramName);
476     fprintf(fp,
477             "OPTIONS:\n"
478             "    -b bitrate      set the bitrate, default 128 kbps\n"
479             "    -h              higher quality, but a little slower.  Recommended.\n"
480             "    -f              fast mode (lower quality)\n"
481             "    -V n            quality setting for VBR.  default n=%i\n"
482             "                    0=high quality,bigger files. 9=smaller files\n",
483             lame_get_VBR_q(gfp));
484     fprintf(fp,
485             "    --preset type   type must be \"medium\", \"standard\", \"extreme\", \"insane\",\n"
486             "                    or a value for an average desired bitrate and depending\n"
487             "                    on the value specified, appropriate quality settings will\n"
488             "                    be used.\n"
489             "                    \"--preset help\" gives more info on these\n" "\n");
490     fprintf(fp,
491 #if defined(WIN32)
492             "    --priority type  sets the process priority\n"
493             "                     0,1 = Low priority\n"
494             "                     2   = normal priority\n"
495             "                     3,4 = High priority\n" "\n"
496 #endif
497 #if defined(__OS2__)
498             "    --priority type  sets the process priority\n"
499             "                     0 = Low priority\n"
500             "                     1 = Medium priority\n"
501             "                     2 = Regular priority\n"
502             "                     3 = High priority\n"
503             "                     4 = Maximum priority\n" "\n"
504 #endif
505             "    --help id3      ID3 tagging related options\n" "\n"
506             DEV_HELP(
507             "    --help dev      developer options\n" "\n"
508             )
509             "    --longhelp      full list of options\n" "\n"
510             "    --license       print License information\n\n"
511             );
512 
513     return 0;
514 }
515 
516 /************************************************************************
517 *
518 * usage
519 *
520 * PURPOSE:  Writes command line syntax to the file specified by fp
521 *
522 ************************************************************************/
523 
524 static void
wait_for(FILE * const fp,int lessmode)525 wait_for(FILE * const fp, int lessmode)
526 {
527     if (lessmode) {
528         fflush(fp);
529         getchar();
530     }
531     else {
532         fprintf(fp, "\n");
533     }
534     fprintf(fp, "\n");
535 }
536 
537 static void
help_id3tag(FILE * const fp)538 help_id3tag(FILE * const fp)
539 {
540     fprintf(fp,
541             "  ID3 tag options:\n"
542             "    --tt <title>    audio/song title (max 30 chars for version 1 tag)\n"
543             "    --ta <artist>   audio/song artist (max 30 chars for version 1 tag)\n"
544             "    --tl <album>    audio/song album (max 30 chars for version 1 tag)\n"
545             "    --ty <year>     audio/song year of issue (1 to 9999)\n"
546             "    --tc <comment>  user-defined text (max 30 chars for v1 tag, 28 for v1.1)\n"
547             "    --tn <track[/total]>   audio/song track number and (optionally) the total\n"
548             "                           number of tracks on the original recording. (track\n"
549             "                           and total each 1 to 255. just the track number\n"
550             "                           creates v1.1 tag, providing a total forces v2.0).\n"
551             "    --tg <genre>    audio/song genre (name or number in list)\n"
552             "    --ti <file>     audio/song albumArt (jpeg/png/gif file, v2.3 tag)\n"
553             "    --tv <id=value> user-defined frame specified by id and value (v2.3 tag)\n"
554             );
555     fprintf(fp,
556             "    --add-id3v2     force addition of version 2 tag\n"
557             "    --id3v1-only    add only a version 1 tag\n"
558             "    --id3v2-only    add only a version 2 tag\n"
559 #ifdef ID3TAGS_EXTENDED
560             "    --id3v2-utf16   add following options in unicode text encoding\n"
561             "    --id3v2-latin1  add following options in latin-1 text encoding\n"
562 #endif
563             "    --space-id3v1   pad version 1 tag with spaces instead of nulls\n"
564             "    --pad-id3v2     same as '--pad-id3v2-size 128'\n"
565             "    --pad-id3v2-size <value> adds version 2 tag, pad with extra <value> bytes\n"
566             "    --genre-list    print alphabetically sorted ID3 genre list and exit\n"
567             "    --ignore-tag-errors  ignore errors in values passed for tags\n" "\n"
568             );
569     fprintf(fp,
570             "    Note: A version 2 tag will NOT be added unless one of the input fields\n"
571             "    won't fit in a version 1 tag (e.g. the title string is longer than 30\n"
572             "    characters), or the '--add-id3v2' or '--id3v2-only' options are used,\n"
573             "    or output is redirected to stdout.\n"
574             );
575 }
576 
577 static void
help_developer_switches(FILE * const fp)578 help_developer_switches(FILE * const fp)
579 {
580     if ( !internal_opts_enabled ) {
581     fprintf(fp,
582             "    Note: Almost all of the following switches aren't available in this build!\n\n"
583             );
584     }
585     fprintf(fp,
586             "  ATH related:\n"
587             "    --noath         turns ATH down to a flat noise floor\n"
588             "    --athshort      ignore GPSYCHO for short blocks, use ATH only\n"
589             "    --athonly       ignore GPSYCHO completely, use ATH only\n"
590             "    --athtype n     selects between different ATH types [0-4]\n"
591             "    --athlower x    lowers ATH by x dB\n"
592             );
593     fprintf(fp,
594             "    --athaa-type n  ATH auto adjust: 0 'no' else 'loudness based'\n"
595 /** OBSOLETE "    --athaa-loudapprox n   n=1 total energy or n=2 equal loudness curve\n"*/
596             "    --athaa-sensitivity x  activation offset in -/+ dB for ATH auto-adjustment\n"
597             "\n");
598     fprintf(fp,
599             "  PSY related:\n"
600             "    --short         use short blocks when appropriate\n"
601             "    --noshort       do not use short blocks\n"
602             "    --allshort      use only short blocks\n"
603             );
604     fprintf(fp,
605             "(1) --temporal-masking x   x=0 disables, x=1 enables temporal masking effect\n"
606             "    --nssafejoint   M/S switching criterion\n"
607             "    --nsmsfix <arg> M/S switching tuning [effective 0-3.5]\n"
608             "(2) --interch x     adjust inter-channel masking ratio\n"
609             "    --ns-bass x     adjust masking for sfbs  0 -  6 (long)  0 -  5 (short)\n"
610             "    --ns-alto x     adjust masking for sfbs  7 - 13 (long)  6 - 10 (short)\n"
611             "    --ns-treble x   adjust masking for sfbs 14 - 21 (long) 11 - 12 (short)\n"
612             );
613     fprintf(fp,
614             "    --ns-sfb21 x    change ns-treble by x dB for sfb21\n"
615             "    --shortthreshold x,y  short block switching threshold,\n"
616             "                          x for L/R/M channel, y for S channel\n"
617             "    -Z [n]          always do calculate short block maskings\n"
618             "  Noise Shaping related:\n"
619             "(1) --substep n     use pseudo substep noise shaping method types 0-2\n"
620             "(1) -X n[,m]        selects between different noise measurements\n"
621             "                    n for long block, m for short. if m is omitted, m = n\n"
622             " 1: CBR, ABR and VBR-old encoding modes only\n"
623             " 2: ignored\n"
624            );
625 }
626 
627 int
long_help(const lame_global_flags * gfp,FILE * const fp,const char * ProgramName,int lessmode)628 long_help(const lame_global_flags * gfp, FILE * const fp, const char *ProgramName, int lessmode)
629 {                       /* print long syntax help */
630     lame_version_print(fp);
631     fprintf(fp,
632             "usage: %s [options] <infile> [outfile]\n"
633             "\n"
634             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
635             "\n" "RECOMMENDED:\n" "    lame -V2 input.wav output.mp3\n" "\n", ProgramName);
636     fprintf(fp,
637             "OPTIONS:\n"
638             "  Input options:\n"
639             "    --scale <arg>   scale input (multiply PCM data) by <arg>\n"
640             "    --scale-l <arg> scale channel 0 (left) input (multiply PCM data) by <arg>\n"
641             "    --scale-r <arg> scale channel 1 (right) input (multiply PCM data) by <arg>\n"
642 #if (defined HAVE_MPGLIB || defined AMIGA_MPEGA)
643             "    --mp1input      input file is a MPEG Layer I   file\n"
644             "    --mp2input      input file is a MPEG Layer II  file\n"
645             "    --mp3input      input file is a MPEG Layer III file\n"
646 #endif
647             "    --nogap <file1> <file2> <...>\n"
648             "                    gapless encoding for a set of contiguous files\n"
649             "    --nogapout <dir>\n"
650             "                    output dir for gapless encoding (must precede --nogap)\n"
651             "    --nogaptags     allow the use of VBR tags in gapless encoding\n"
652            );
653     fprintf(fp,
654             "\n"
655             "  Input options for RAW PCM:\n"
656             "    -r              input is raw pcm\n"
657             "    -x              force byte-swapping of input\n"
658             "    -s sfreq        sampling frequency of input file (kHz) - default 44.1 kHz\n"
659             "    --bitwidth w    input bit width is w (default 16)\n"
660             "    --signed        input is signed (default)\n"
661             "    --unsigned      input is unsigned\n"
662             "    --little-endian input is little-endian (default)\n"
663             "    --big-endian    input is big-endian\n"
664            );
665 
666     wait_for(fp, lessmode);
667     fprintf(fp,
668             "  Operational options:\n"
669             "    -a              downmix from stereo to mono file for mono encoding\n"
670             "    -m <mode>       (j)oint, (s)imple, (f)orce, (d)ual-mono, (m)ono (l)eft (r)ight\n"
671             "                    default is (j) or (s) depending on bitrate\n"
672             "                    joint  = joins the best possible of MS and LR stereo\n"
673             "                    simple = force LR stereo on all frames\n"
674             "                    force  = force MS stereo on all frames.\n"
675             "    --preset type   type must be \"medium\", \"standard\", \"extreme\", \"insane\",\n"
676             "                    or a value for an average desired bitrate and depending\n"
677             "                    on the value specified, appropriate quality settings will\n"
678             "                    be used.\n"
679             "                    \"--preset help\" gives more info on these\n"
680             "    --comp  <arg>   choose bitrate to achieve a compression ratio of <arg>\n");
681     fprintf(fp, "    --replaygain-fast   compute RG fast but slightly inaccurately (default)\n"
682 #ifdef DECODE_ON_THE_FLY
683             "    --replaygain-accurate   compute RG more accurately and find the peak sample\n"
684 #endif
685             "    --noreplaygain  disable ReplayGain analysis\n"
686 #ifdef DECODE_ON_THE_FLY
687             "    --clipdetect    enable --replaygain-accurate and print a message whether\n"
688             "                    clipping occurs and how far the waveform is from full scale\n"
689 #endif
690         );
691     fprintf(fp,
692             "    --flush         flush output stream as soon as possible\n"
693             "    --freeformat    produce a free format bitstream\n"
694             "    --decode        input=mp3 file, output=wav\n"
695             "    --swap-channel  swap L/R channels\n"
696             "    -t              disable writing wav header when using --decode\n");
697 
698     wait_for(fp, lessmode);
699     fprintf(fp,
700             "  Verbosity:\n"
701             "    --disptime <arg>print progress report every arg seconds\n"
702             "    -S              don't print progress report, VBR histograms\n"
703             "    --nohist        disable VBR histogram display\n"
704             "    --quiet         don't print anything on screen\n"
705             "    --silent        don't print anything on screen, but fatal errors\n"
706             "    --brief         print more useful information\n"
707             "    --verbose       print a lot of useful information\n" "\n");
708     fprintf(fp,
709             "  Noise shaping & psycho acoustic algorithms:\n"
710             "    -q <arg>        <arg> = 0...9.  Default  -q 5 \n"
711             "                    -q 0:  Highest quality, very slow \n"
712             "                    -q 9:  Poor quality, but fast \n"
713             "    -h              Same as -q 2.   Recommended.\n"
714             "    -f              Same as -q 7.   Fast, ok quality\n");
715 
716     wait_for(fp, lessmode);
717     fprintf(fp,
718             "  CBR (constant bitrate, the default) options:\n"
719             "    -b <bitrate>    set the bitrate in kbps, default 128 kbps\n"
720             "    --cbr           enforce use of constant bitrate\n"
721             "\n"
722             "  ABR options:\n"
723             "    --abr <bitrate> specify average bitrate desired (instead of quality)\n" "\n");
724     fprintf(fp,
725             "  VBR options:\n"
726             "    -V n            quality setting for VBR.  default n=%i\n"
727             "                    0=high quality,bigger files. 9=smaller files\n"
728             "    -v              the same as -V 4\n"
729             "    --vbr-old       use old variable bitrate (VBR) routine\n"
730             "    --vbr-new       use new variable bitrate (VBR) routine (default)\n"
731             "    -Y              lets LAME ignore noise in sfb21, like in CBR\n"
732             ,
733             lame_get_VBR_q(gfp));
734     fprintf(fp,
735             "    -b <bitrate>    specify minimum allowed bitrate, default  32 kbps\n"
736             "    -B <bitrate>    specify maximum allowed bitrate, default 320 kbps\n"
737             "    -F              strictly enforce the -b option, for use with players that\n"
738             "                    do not support low bitrate mp3\n"
739             "    -t              disable writing LAME Tag\n"
740             "    -T              enable and force writing LAME Tag\n");
741 
742     wait_for(fp, lessmode);
743     DEV_HELP(
744         help_developer_switches(fp);
745         wait_for(fp, lessmode);
746             )
747 
748     fprintf(fp,
749             "  MP3 header/stream options:\n"
750             "    -e <emp>        de-emphasis n/5/c  (obsolete)\n"
751             "    -c              mark as copyright\n"
752             "    -o              mark as non-original\n"
753             "    -p              error protection.  adds 16 bit checksum to every frame\n"
754             "                    (the checksum is computed correctly)\n"
755             "    --nores         disable the bit reservoir\n"
756             "    --strictly-enforce-ISO   comply as much as possible to ISO MPEG spec\n");
757     fprintf(fp,
758             "    --buffer-constraint <constraint> available values for constraint:\n"
759             "                                     default, strict, maximum\n"
760             "\n"
761             );
762     fprintf(fp,
763             "  Filter options:\n"
764             "  --lowpass <freq>        frequency(kHz), lowpass filter cutoff above freq\n"
765             "  --lowpass-width <freq>  frequency(kHz) - default 15%% of lowpass freq\n"
766             "  --highpass <freq>       frequency(kHz), highpass filter cutoff below freq\n"
767             "  --highpass-width <freq> frequency(kHz) - default 15%% of highpass freq\n");
768     fprintf(fp,
769             "  --resample <sfreq>  sampling frequency of output file(kHz)- default=automatic\n");
770 
771     wait_for(fp, lessmode);
772     help_id3tag(fp);
773     fprintf(fp,
774 #if defined(WIN32)
775             "\n\nMS-Windows-specific options:\n"
776             "    --priority <type>  sets the process priority:\n"
777             "                         0,1 = Low priority (IDLE_PRIORITY_CLASS)\n"
778             "                         2 = normal priority (NORMAL_PRIORITY_CLASS, default)\n"
779             "                         3,4 = High priority (HIGH_PRIORITY_CLASS))\n"
780             "    Note: Calling '--priority' without a parameter will select priority 0.\n"
781 #endif
782 #if defined(__OS2__)
783             "\n\nOS/2-specific options:\n"
784             "    --priority <type>  sets the process priority:\n"
785             "                         0 = Low priority (IDLE, delta = 0)\n"
786             "                         1 = Medium priority (IDLE, delta = +31)\n"
787             "                         2 = Regular priority (REGULAR, delta = -31)\n"
788             "                         3 = High priority (REGULAR, delta = 0)\n"
789             "                         4 = Maximum priority (REGULAR, delta = +31)\n"
790             "    Note: Calling '--priority' without a parameter will select priority 0.\n"
791 #endif
792             "\nMisc:\n    --license       print License information\n\n"
793         );
794 
795 #if defined(HAVE_NASM)
796     wait_for(fp, lessmode);
797     fprintf(fp,
798             "  Platform specific:\n"
799             "    --noasm <instructions> disable assembly optimizations for mmx/3dnow/sse\n");
800     wait_for(fp, lessmode);
801 #endif
802 
803     display_bitrates(fp);
804 
805     return 0;
806 }
807 
808 static void
display_bitrate(FILE * const fp,const char * const version,const int d,const int indx)809 display_bitrate(FILE * const fp, const char *const version, const int d, const int indx)
810 {
811     int     i;
812     int nBitrates = 14;
813     if (d == 4)
814         nBitrates = 8;
815 
816 
817     fprintf(fp,
818             "\nMPEG-%-3s layer III sample frequencies (kHz):  %2d  %2d  %g\n"
819             "bitrates (kbps):", version, 32 / d, 48 / d, 44.1 / d);
820     for (i = 1; i <= nBitrates; i++)
821         fprintf(fp, " %2i", lame_get_bitrate(indx, i));
822     fprintf(fp, "\n");
823 }
824 
825 int
display_bitrates(FILE * const fp)826 display_bitrates(FILE * const fp)
827 {
828     display_bitrate(fp, "1", 1, 1);
829     display_bitrate(fp, "2", 2, 0);
830     display_bitrate(fp, "2.5", 4, 0);
831     fprintf(fp, "\n");
832     fflush(fp);
833     return 0;
834 }
835 
836 
837 /*  note: for presets it would be better to externalize them in a file.
838     suggestion:  lame --preset <file-name> ...
839             or:  lame --preset my-setting  ... and my-setting is defined in lame.ini
840  */
841 
842 /*
843 Note from GB on 08/25/2002:
844 I am merging --presets and --alt-presets. Old presets are now aliases for
845 corresponding abr values from old alt-presets. This way we now have a
846 unified preset system, and I hope than more people will use the new tuned
847 presets instead of the old unmaintained ones.
848 */
849 
850 
851 
852 /************************************************************************
853 *
854 * usage
855 *
856 * PURPOSE:  Writes presetting info to #stdout#
857 *
858 ************************************************************************/
859 
860 
861 static void
presets_longinfo_dm(FILE * msgfp)862 presets_longinfo_dm(FILE * msgfp)
863 {
864     fprintf(msgfp,
865             "\n"
866             "The --preset switches are aliases over LAME settings.\n"
867             "\n" "\n");
868     fprintf(msgfp,
869             "To activate these presets:\n"
870             "\n" "   For VBR modes (generally highest quality):\n" "\n");
871     fprintf(msgfp,
872             "     \"--preset medium\" This preset should provide near transparency\n"
873             "                             to most people on most music.\n"
874             "\n"
875             "     \"--preset standard\" This preset should generally be transparent\n"
876             "                             to most people on most music and is already\n"
877             "                             quite high in quality.\n" "\n");
878     fprintf(msgfp,
879             "     \"--preset extreme\" If you have extremely good hearing and similar\n"
880             "                             equipment, this preset will generally provide\n"
881             "                             slightly higher quality than the \"standard\"\n"
882             "                             mode.\n" "\n");
883     fprintf(msgfp,
884             "   For CBR 320kbps (highest quality possible from the --preset switches):\n"
885             "\n"
886             "     \"--preset insane\"  This preset will usually be overkill for most\n"
887             "                             people and most situations, but if you must\n"
888             "                             have the absolute highest quality with no\n"
889             "                             regard to filesize, this is the way to go.\n" "\n");
890     fprintf(msgfp,
891             "   For ABR modes (high quality per given bitrate but not as high as VBR):\n"
892             "\n"
893             "     \"--preset <kbps>\"  Using this preset will usually give you good\n"
894             "                             quality at a specified bitrate. Depending on the\n"
895             "                             bitrate entered, this preset will determine the\n");
896     fprintf(msgfp,
897             "                             optimal settings for that particular situation.\n"
898             "                             While this approach works, it is not nearly as\n"
899             "                             flexible as VBR, and usually will not attain the\n"
900             "                             same level of quality as VBR at higher bitrates.\n" "\n");
901     fprintf(msgfp,
902             "The following options are also available for the corresponding profiles:\n"
903             "\n"
904             "                 standard\n"
905             "                 extreme\n"
906             "                 insane\n"
907             "   <cbr> (ABR Mode) - The ABR Mode is implied. To use it,\n"
908             "                      simply specify a bitrate. For example:\n"
909             "                      \"--preset 185\" activates this\n"
910             "                      preset and uses 185 as an average kbps.\n" "\n");
911     fprintf(msgfp,
912             "   \"cbr\"  - If you use the ABR mode (read above) with a significant\n"
913             "            bitrate such as 80, 96, 112, 128, 160, 192, 224, 256, 320,\n"
914             "            you can use the \"cbr\" option to force CBR mode encoding\n"
915             "            instead of the standard abr mode. ABR does provide higher\n"
916             "            quality but CBR may be useful in situations such as when\n"
917             "            streaming an mp3 over the internet may be important.\n" "\n");
918     fprintf(msgfp,
919             "    For example:\n"
920             "\n"
921             "    \"--preset standard <input file> <output file>\"\n"
922             " or \"--preset cbr 192 <input file> <output file>\"\n"
923             " or \"--preset 172 <input file> <output file>\"\n"
924             " or \"--preset extreme <input file> <output file>\"\n" "\n" "\n");
925     fprintf(msgfp,
926             "A few aliases are also available for ABR mode:\n"
927             "phone => 16kbps/mono        phon+/lw/mw-eu/sw => 24kbps/mono\n"
928             "mw-us => 40kbps/mono        voice => 56kbps/mono\n"
929             "fm/radio/tape => 112kbps    hifi => 160kbps\n"
930             "cd => 192kbps               studio => 256kbps\n");
931 }
932 
933 
934 static int
presets_set(lame_t gfp,int fast,int cbr,const char * preset_name,const char * ProgramName)935 presets_set(lame_t gfp, int fast, int cbr, const char *preset_name, const char *ProgramName)
936 {
937     int     mono = 0;
938 
939     if ((strcmp(preset_name, "help") == 0) && (fast < 1)
940         && (cbr < 1)) {
941         lame_version_print(stdout);
942         presets_longinfo_dm(stdout);
943         return -1;
944     }
945 
946     /*aliases for compatibility with old presets */
947 
948     if (strcmp(preset_name, "phone") == 0) {
949         preset_name = "16";
950         mono = 1;
951     }
952     if ((strcmp(preset_name, "phon+") == 0) ||
953         (strcmp(preset_name, "lw") == 0) ||
954         (strcmp(preset_name, "mw-eu") == 0) || (strcmp(preset_name, "sw") == 0)) {
955         preset_name = "24";
956         mono = 1;
957     }
958     if (strcmp(preset_name, "mw-us") == 0) {
959         preset_name = "40";
960         mono = 1;
961     }
962     if (strcmp(preset_name, "voice") == 0) {
963         preset_name = "56";
964         mono = 1;
965     }
966     if (strcmp(preset_name, "fm") == 0) {
967         preset_name = "112";
968     }
969     if ((strcmp(preset_name, "radio") == 0) || (strcmp(preset_name, "tape") == 0)) {
970         preset_name = "112";
971     }
972     if (strcmp(preset_name, "hifi") == 0) {
973         preset_name = "160";
974     }
975     if (strcmp(preset_name, "cd") == 0) {
976         preset_name = "192";
977     }
978     if (strcmp(preset_name, "studio") == 0) {
979         preset_name = "256";
980     }
981 
982     if (strcmp(preset_name, "medium") == 0) {
983         lame_set_VBR_q(gfp, 4);
984         lame_set_VBR(gfp, vbr_default);
985         return 0;
986     }
987 
988     if (strcmp(preset_name, "standard") == 0) {
989         lame_set_VBR_q(gfp, 2);
990         lame_set_VBR(gfp, vbr_default);
991         return 0;
992     }
993 
994     else if (strcmp(preset_name, "extreme") == 0) {
995         lame_set_VBR_q(gfp, 0);
996         lame_set_VBR(gfp, vbr_default);
997         return 0;
998     }
999 
1000     else if ((strcmp(preset_name, "insane") == 0) && (fast < 1)) {
1001 
1002         lame_set_preset(gfp, INSANE);
1003 
1004         return 0;
1005     }
1006 
1007     /* Generic ABR Preset */
1008     if (((atoi(preset_name)) > 0) && (fast < 1)) {
1009         if ((atoi(preset_name)) >= 8 && (atoi(preset_name)) <= 320) {
1010             lame_set_preset(gfp, atoi(preset_name));
1011 
1012             if (cbr == 1)
1013                 lame_set_VBR(gfp, vbr_off);
1014 
1015             if (mono == 1) {
1016                 lame_set_mode(gfp, MONO);
1017             }
1018 
1019             return 0;
1020 
1021         }
1022         else {
1023             lame_version_print(Console_IO.Error_fp);
1024             error_printf("Error: The bitrate specified is out of the valid range for this preset\n"
1025                          "\n"
1026                          "When using this mode you must enter a value between \"32\" and \"320\"\n"
1027                          "\n" "For further information try: \"%s --preset help\"\n", ProgramName);
1028             return -1;
1029         }
1030     }
1031 
1032     lame_version_print(Console_IO.Error_fp);
1033     error_printf("Error: You did not enter a valid profile and/or options with --preset\n"
1034                  "\n"
1035                  "Available profiles are:\n"
1036                  "\n"
1037                  "                 medium\n"
1038                  "                 standard\n"
1039                  "                 extreme\n"
1040                  "                 insane\n"
1041                  "          <cbr> (ABR Mode) - The ABR Mode is implied. To use it,\n"
1042                  "                             simply specify a bitrate. For example:\n"
1043                  "                             \"--preset 185\" activates this\n"
1044                  "                             preset and uses 185 as an average kbps.\n" "\n");
1045     error_printf("    Some examples:\n"
1046                  "\n"
1047                  " or \"%s --preset standard <input file> <output file>\"\n"
1048                  " or \"%s --preset cbr 192 <input file> <output file>\"\n"
1049                  " or \"%s --preset 172 <input file> <output file>\"\n"
1050                  " or \"%s --preset extreme <input file> <output file>\"\n"
1051                  "\n"
1052                  "For further information try: \"%s --preset help\"\n", ProgramName, ProgramName,
1053                  ProgramName, ProgramName, ProgramName);
1054     return -1;
1055 }
1056 
1057 static void
genre_list_handler(int num,const char * name,void * cookie)1058 genre_list_handler(int num, const char *name, void *cookie)
1059 {
1060     (void) cookie;
1061     console_printf("%3d %s\n", num, name);
1062 }
1063 
1064 
1065 /************************************************************************
1066 *
1067 * parse_args
1068 *
1069 * PURPOSE:  Sets encoding parameters to the specifications of the
1070 * command line.  Default settings are used for parameters
1071 * not specified in the command line.
1072 *
1073 * If the input file is in WAVE or AIFF format, the sampling frequency is read
1074 * from the AIFF header.
1075 *
1076 * The input and output filenames are read into #inpath# and #outpath#.
1077 *
1078 ************************************************************************/
1079 
1080 /* would use real "strcasecmp" but it isn't portable */
1081 static int
local_strcasecmp(const char * s1,const char * s2)1082 local_strcasecmp(const char *s1, const char *s2)
1083 {
1084     unsigned char c1;
1085     unsigned char c2;
1086 
1087     do {
1088         c1 = (unsigned char) tolower(*s1);
1089         c2 = (unsigned char) tolower(*s2);
1090         if (!c1) {
1091             break;
1092         }
1093         ++s1;
1094         ++s2;
1095     } while (c1 == c2);
1096     return c1 - c2;
1097 }
1098 
1099 static int
local_strncasecmp(const char * s1,const char * s2,int n)1100 local_strncasecmp(const char *s1, const char *s2, int n)
1101 {
1102     unsigned char c1 = 0;
1103     unsigned char c2 = 0;
1104     int     cnt = 0;
1105 
1106     do {
1107         if (cnt == n) {
1108             break;
1109         }
1110         c1 = (unsigned char) tolower(*s1);
1111         c2 = (unsigned char) tolower(*s2);
1112         if (!c1) {
1113             break;
1114         }
1115         ++s1;
1116         ++s2;
1117         ++cnt;
1118     } while (c1 == c2);
1119     return c1 - c2;
1120 }
1121 
1122 
1123 
1124 /* LAME is a simple frontend which just uses the file extension */
1125 /* to determine the file type.  Trying to analyze the file */
1126 /* contents is well beyond the scope of LAME and should not be added. */
1127 static int
filename_to_type(const char * FileName)1128 filename_to_type(const char *FileName)
1129 {
1130     size_t  len = strlen(FileName);
1131 
1132     if (len < 4)
1133         return sf_unknown;
1134 
1135     FileName += len - 4;
1136     if (0 == local_strcasecmp(FileName, ".mpg"))
1137         return sf_mp123;
1138     if (0 == local_strcasecmp(FileName, ".mp1"))
1139         return sf_mp123;
1140     if (0 == local_strcasecmp(FileName, ".mp2"))
1141         return sf_mp123;
1142     if (0 == local_strcasecmp(FileName, ".mp3"))
1143         return sf_mp123;
1144     if (0 == local_strcasecmp(FileName, ".wav"))
1145         return sf_wave;
1146     if (0 == local_strcasecmp(FileName, ".aif"))
1147         return sf_aiff;
1148     if (0 == local_strcasecmp(FileName, ".raw"))
1149         return sf_raw;
1150     if (0 == local_strcasecmp(FileName, ".ogg"))
1151         return sf_ogg;
1152     return sf_unknown;
1153 }
1154 
1155 static int
resample_rate(double freq)1156 resample_rate(double freq)
1157 {
1158     if (freq >= 1.e3)
1159         freq *= 1.e-3;
1160 
1161     switch ((int) freq) {
1162     case 8:
1163         return 8000;
1164     case 11:
1165         return 11025;
1166     case 12:
1167         return 12000;
1168     case 16:
1169         return 16000;
1170     case 22:
1171         return 22050;
1172     case 24:
1173         return 24000;
1174     case 32:
1175         return 32000;
1176     case 44:
1177         return 44100;
1178     case 48:
1179         return 48000;
1180     default:
1181         error_printf("Illegal resample frequency: %.3f kHz\n", freq);
1182         return 0;
1183     }
1184 }
1185 
1186 #ifdef _WIN32
1187 #define SLASH '\\'
1188 #elif __OS2__
1189 #define SLASH '\\'
1190 #else
1191 #define SLASH '/'
1192 #endif
1193 
1194 static
scanPath(char const * s,char const ** a,char const ** b)1195 size_t scanPath(char const* s, char const** a, char const** b)
1196 {
1197     char const* s1 = s;
1198     char const* s2 = s;
1199     if (s != 0) {
1200         for (; *s; ++s) {
1201             switch (*s) {
1202             case SLASH:
1203             case ':':
1204                 s2 = s;
1205                 break;
1206             }
1207         }
1208         if (*s2 == ':') {
1209             ++s2;
1210         }
1211     }
1212     if (a) {
1213         *a = s1;
1214     }
1215     if (b) {
1216         *b = s2;
1217     }
1218     return s2-s1;
1219 }
1220 
1221 static
scanBasename(char const * s,char const ** a,char const ** b)1222 size_t scanBasename(char const* s, char const** a, char const** b)
1223 {
1224     char const* s1 = s;
1225     char const* s2 = s;
1226     if (s != 0) {
1227         for (; *s; ++s) {
1228             switch (*s) {
1229             case SLASH:
1230             case ':':
1231                 s1 = s2 = s;
1232                 break;
1233             case '.':
1234                 s2 = s;
1235                 break;
1236             }
1237         }
1238         if (s2 == s1) {
1239             s2 = s;
1240         }
1241         if (*s1 == SLASH || *s1 == ':') {
1242             ++s1;
1243         }
1244     }
1245     if (a != 0) {
1246         *a = s1;
1247     }
1248     if (b != 0) {
1249         *b = s2;
1250     }
1251     return s2-s1;
1252 }
1253 
1254 static
isCommonSuffix(char const * s_ext)1255 int isCommonSuffix(char const* s_ext)
1256 {
1257     char const* suffixes[] =
1258     { ".WAV", ".RAW", ".MP1", ".MP2"
1259     , ".MP3", ".MPG", ".MPA", ".CDA"
1260     , ".OGG", ".AIF", ".AIFF", ".AU"
1261     , ".SND", ".FLAC", ".WV", ".OFR"
1262     , ".TAK", ".MP4", ".M4A", ".PCM"
1263     , ".W64"
1264     };
1265     size_t i;
1266     for (i = 0; i < dimension_of(suffixes); ++i) {
1267         if (local_strcasecmp(s_ext, suffixes[i]) == 0) {
1268             return 1;
1269         }
1270     }
1271     return 0;
1272 }
1273 
1274 
1275 static
generateOutPath(lame_t gfp,char const * inPath,char const * outDir,char * outPath)1276 int generateOutPath(lame_t gfp, char const* inPath, char const* outDir, char* outPath)
1277 {
1278     size_t const max_path = PATH_MAX;
1279     char const* s_ext = lame_get_decode_only(gfp) ? ".wav" : ".mp3";
1280 #if 1
1281     size_t i = 0;
1282     int out_dir_used = 0;
1283 
1284     if (outDir != 0 && outDir[0] != 0) {
1285         out_dir_used = 1;
1286         while (*outDir) {
1287             outPath[i++] = *outDir++;
1288             if (i >= max_path) {
1289                 goto err_generateOutPath;
1290             }
1291         }
1292         if (i > 0 && outPath[i-1] != SLASH) {
1293             outPath[i++] = SLASH;
1294             if (i >= max_path) {
1295                 goto err_generateOutPath;
1296             }
1297         }
1298         outPath[i] = 0;
1299     }
1300     else {
1301         char const* pa;
1302         char const* pb;
1303         size_t j, n = scanPath(inPath, &pa, &pb);
1304         if (i+n >= max_path) {
1305             goto err_generateOutPath;
1306         }
1307         for (j = 0; j < n; ++j) {
1308             outPath[i++] = pa[j];
1309         }
1310         if (n > 0) {
1311             outPath[i++] = SLASH;
1312             if (i >= max_path) {
1313                 goto err_generateOutPath;
1314             }
1315         }
1316         outPath[i] = 0;
1317     }
1318     {
1319         int replace_suffix = 0;
1320         char const* na;
1321         char const* nb;
1322         size_t j, n = scanBasename(inPath, &na, &nb);
1323         if (i+n >= max_path) {
1324             goto err_generateOutPath;
1325         }
1326         for (j = 0; j < n; ++j) {
1327             outPath[i++] = na[j];
1328         }
1329         outPath[i] = 0;
1330         if (isCommonSuffix(nb) == 1) {
1331             replace_suffix = 1;
1332             if (out_dir_used == 0) {
1333                 if (local_strcasecmp(nb, s_ext) == 0) {
1334                     replace_suffix = 0;
1335                 }
1336             }
1337         }
1338         if (replace_suffix == 0) {
1339             while (*nb) {
1340                 outPath[i++] = *nb++;
1341                 if (i >= max_path) {
1342                     goto err_generateOutPath;
1343                 }
1344             }
1345             outPath[i] = 0;
1346         }
1347     }
1348     if (i+5 >= max_path) {
1349         goto err_generateOutPath;
1350     }
1351     while (*s_ext) {
1352         outPath[i++] = *s_ext++;
1353     }
1354     outPath[i] = 0;
1355     return 0;
1356 err_generateOutPath:
1357     error_printf( "error: output file name too long" );
1358     return 1;
1359 #else
1360     strncpy(outPath, inPath, PATH_MAX + 1 - 4);
1361     strncat(outPath, s_ext, 4);
1362     return 0;
1363 #endif
1364 }
1365 
1366 
1367 static int
set_id3_albumart(lame_t gfp,char const * file_name)1368 set_id3_albumart(lame_t gfp, char const* file_name)
1369 {
1370     int ret = -1;
1371     FILE *fpi = 0;
1372     char *albumart = 0;
1373 
1374     if (file_name == 0) {
1375         return 0;
1376     }
1377     fpi = lame_fopen(file_name, "rb");
1378     if (!fpi) {
1379         ret = 1;
1380     }
1381     else {
1382         size_t size;
1383 
1384         fseek(fpi, 0, SEEK_END);
1385         size = ftell(fpi);
1386         fseek(fpi, 0, SEEK_SET);
1387         albumart = (char *)malloc(size);
1388         if (!albumart) {
1389             ret = 2;
1390         }
1391         else {
1392             if (fread(albumart, 1, size, fpi) != size) {
1393                 ret = 3;
1394             }
1395             else {
1396                 ret = id3tag_set_albumart(gfp, albumart, size) ? 4 : 0;
1397             }
1398             free(albumart);
1399         }
1400         fclose(fpi);
1401     }
1402     switch (ret) {
1403     case 1: error_printf("Could not find: '%s'.\n", file_name); break;
1404     case 2: error_printf("Insufficient memory for reading the albumart.\n"); break;
1405     case 3: error_printf("Read error: '%s'.\n", file_name); break;
1406     case 4: error_printf("Unsupported image: '%s'.\nSpecify JPEG/PNG/GIF image\n", file_name); break;
1407     default: break;
1408     }
1409     return ret;
1410 }
1411 
1412 
1413 enum ID3TAG_MODE
1414 { ID3TAG_MODE_DEFAULT
1415 , ID3TAG_MODE_V1_ONLY
1416 , ID3TAG_MODE_V2_ONLY
1417 };
1418 
1419 /* Ugly, NOT final version */
1420 
1421 #define T_IF(str)          if ( 0 == local_strcasecmp (token,str) ) {
1422 #define T_ELIF(str)        } else if ( 0 == local_strcasecmp (token,str) ) {
1423 #define T_ELIF_INTERNAL(str) } else if (internal_opts_enabled && (0 == local_strcasecmp (token,str)) ) {
1424 #define T_ELIF2(str1,str2) } else if ( 0 == local_strcasecmp (token,str1)  ||  0 == local_strcasecmp (token,str2) ) {
1425 #define T_ELSE             } else {
1426 #define T_END              }
1427 
1428 int
parse_args(lame_global_flags * gfp,int argc,char ** argv,char * const inPath,char * const outPath,char ** nogap_inPath,int * num_nogap)1429 parse_args(lame_global_flags * gfp, int argc, char **argv,
1430            char *const inPath, char *const outPath, char **nogap_inPath, int *num_nogap)
1431 {
1432     char    outDir[1024] = "";
1433     int     input_file = 0;  /* set to 1 if we parse an input file name  */
1434     int     i;
1435     int     autoconvert = 0;
1436     double  val;
1437     int     nogap = 0;
1438     int     nogap_tags = 0;  /* set to 1 to use VBR tags in NOGAP mode */
1439     const char *ProgramName = argv[0];
1440     int     count_nogap = 0;
1441     int     noreplaygain = 0; /* is RG explicitly disabled by the user */
1442     int     id3tag_mode = ID3TAG_MODE_DEFAULT;
1443     int     ignore_tag_errors = 0;  /* Ignore errors in values passed for tags */
1444 #ifdef ID3TAGS_EXTENDED
1445     enum TextEncoding id3_tenc = TENC_UTF16;
1446 #else
1447     enum TextEncoding id3_tenc = TENC_LATIN1;
1448 #endif
1449 
1450     inPath[0] = '\0';
1451     outPath[0] = '\0';
1452     /* turn on display options. user settings may turn them off below */
1453     global_ui_config.silent = 0;
1454     global_ui_config.brhist = 1;
1455     global_decoder.mp3_delay = 0;
1456     global_decoder.mp3_delay_set = 0;
1457     global_decoder.disable_wav_header = 0;
1458     global_ui_config.print_clipping_info = 0;
1459     id3tag_init(gfp);
1460 
1461     /* process args */
1462     for (i = 0; ++i < argc;) {
1463         char    c;
1464         char   *token;
1465         char   *arg;
1466         char   *nextArg;
1467         int     argUsed;
1468 
1469         token = argv[i];
1470         if (*token++ == '-') {
1471             argUsed = 0;
1472             nextArg = i + 1 < argc ? argv[i + 1] : "";
1473 
1474             if (!*token) { /* The user wants to use stdin and/or stdout. */
1475                 input_file = 1;
1476                 if (inPath[0] == '\0')
1477                     strncpy(inPath, argv[i], PATH_MAX + 1);
1478                 else if (outPath[0] == '\0')
1479                     strncpy(outPath, argv[i], PATH_MAX + 1);
1480             }
1481             if (*token == '-') { /* GNU style */
1482                 token++;
1483 
1484                 T_IF("resample")
1485                     argUsed = 1;
1486                 (void) lame_set_out_samplerate(gfp, resample_rate(atof(nextArg)));
1487 
1488                 T_ELIF("vbr-old")
1489                     lame_set_VBR(gfp, vbr_rh);
1490 
1491                 T_ELIF("vbr-new")
1492                     lame_set_VBR(gfp, vbr_mt);
1493 
1494                 T_ELIF("vbr-mtrh")
1495                     lame_set_VBR(gfp, vbr_mtrh);
1496 
1497                 T_ELIF("cbr")
1498                     lame_set_VBR(gfp, vbr_off);
1499 
1500                 T_ELIF("abr")
1501                     /* values larger than 8000 are bps (like Fraunhofer), so it's strange to get 320000 bps MP3 when specifying 8000 bps MP3 */
1502                     int m = atoi(nextArg);
1503                     argUsed = 1;
1504                     if (m >= 8000) {
1505                         m = (m + 500) / 1000;
1506                     }
1507                     if (m > 320) {
1508                         m = 320;
1509                     }
1510                     if (m < 8) {
1511                         m = 8;
1512                     }
1513                     lame_set_VBR(gfp, vbr_abr);
1514                     lame_set_VBR_mean_bitrate_kbps(gfp, m);
1515 
1516                 T_ELIF("r3mix")
1517                     lame_set_preset(gfp, R3MIX);
1518 
1519                 T_ELIF("bitwidth")
1520                     argUsed = 1;
1521                     global_raw_pcm.in_bitwidth = atoi(nextArg);
1522 
1523                 T_ELIF("signed")
1524                     global_raw_pcm.in_signed = 1;
1525 
1526                 T_ELIF("unsigned")
1527                     global_raw_pcm.in_signed = 0;
1528 
1529                 T_ELIF("little-endian")
1530                     global_raw_pcm.in_endian = ByteOrderLittleEndian;
1531 
1532                 T_ELIF("big-endian")
1533                     global_raw_pcm.in_endian = ByteOrderBigEndian;
1534 
1535                 T_ELIF("mp1input")
1536                     global_reader.input_format = sf_mp1;
1537 
1538                 T_ELIF("mp2input")
1539                     global_reader.input_format = sf_mp2;
1540 
1541                 T_ELIF("mp3input")
1542                     global_reader.input_format = sf_mp3;
1543 
1544                 T_ELIF("ogginput")
1545                     error_printf("sorry, vorbis support in LAME is deprecated.\n");
1546                 return -1;
1547 #if INTERNAL_OPTS
1548                 T_ELIF_INTERNAL("noshort")
1549                     (void) lame_set_no_short_blocks(gfp, 1);
1550 
1551                 T_ELIF_INTERNAL("short")
1552                     (void) lame_set_no_short_blocks(gfp, 0);
1553 
1554                 T_ELIF_INTERNAL("allshort")
1555                     (void) lame_set_force_short_blocks(gfp, 1);
1556 #endif
1557 
1558                 T_ELIF("decode")
1559                     (void) lame_set_decode_only(gfp, 1);
1560 
1561                 T_ELIF("flush")
1562                     global_writer.flush_write = 1;
1563 
1564                 T_ELIF("decode-mp3delay")
1565                     global_decoder.mp3_delay = atoi(nextArg);
1566                     global_decoder.mp3_delay_set = 1;
1567                     argUsed = 1;
1568 
1569                 T_ELIF("nores")
1570                     lame_set_disable_reservoir(gfp, 1);
1571 
1572                 T_ELIF("strictly-enforce-ISO")
1573                     lame_set_strict_ISO(gfp, MDB_STRICT_ISO);
1574 
1575                 T_ELIF("buffer-constraint")
1576                   argUsed = 1;
1577                 if (strcmp(nextArg, "default") == 0)
1578                   (void) lame_set_strict_ISO(gfp, MDB_DEFAULT);
1579                 else if (strcmp(nextArg, "strict") == 0)
1580                   (void) lame_set_strict_ISO(gfp, MDB_STRICT_ISO);
1581                 else if (strcmp(nextArg, "maximum") == 0)
1582                   (void) lame_set_strict_ISO(gfp, MDB_MAXIMUM);
1583                 else {
1584                     error_printf("unknown buffer constraint '%s'\n", nextArg);
1585                     return -1;
1586                 }
1587 
1588                 T_ELIF("scale")
1589                     argUsed = 1;
1590                 (void) lame_set_scale(gfp, (float) atof(nextArg));
1591 
1592                 T_ELIF("scale-l")
1593                     argUsed = 1;
1594                 (void) lame_set_scale_left(gfp, (float) atof(nextArg));
1595 
1596                 T_ELIF("scale-r")
1597                     argUsed = 1;
1598                 (void) lame_set_scale_right(gfp, (float) atof(nextArg));
1599 
1600                 T_ELIF("noasm")
1601                     argUsed = 1;
1602                 if (!strcmp(nextArg, "mmx"))
1603                     (void) lame_set_asm_optimizations(gfp, MMX, 0);
1604                 if (!strcmp(nextArg, "3dnow"))
1605                     (void) lame_set_asm_optimizations(gfp, AMD_3DNOW, 0);
1606                 if (!strcmp(nextArg, "sse"))
1607                     (void) lame_set_asm_optimizations(gfp, SSE, 0);
1608 
1609                 T_ELIF("freeformat")
1610                     lame_set_free_format(gfp, 1);
1611 
1612                 T_ELIF("replaygain-fast")
1613                     lame_set_findReplayGain(gfp, 1);
1614 
1615 #ifdef DECODE_ON_THE_FLY
1616                 T_ELIF("replaygain-accurate")
1617                     lame_set_decode_on_the_fly(gfp, 1);
1618                 lame_set_findReplayGain(gfp, 1);
1619 #endif
1620 
1621                 T_ELIF("noreplaygain")
1622                     noreplaygain = 1;
1623                 lame_set_findReplayGain(gfp, 0);
1624 
1625 
1626 #ifdef DECODE_ON_THE_FLY
1627                 T_ELIF("clipdetect")
1628                     global_ui_config.print_clipping_info = 1;
1629                     lame_set_decode_on_the_fly(gfp, 1);
1630 #endif
1631 
1632                 T_ELIF("nohist")
1633                     global_ui_config.brhist = 0;
1634 
1635 #if defined(__OS2__) || defined(WIN32)
1636                 T_ELIF("priority")
1637                 char   *endptr;
1638                 int     priority = (int) strtol(nextArg, &endptr, 10);
1639                 if (endptr != nextArg) {
1640                     argUsed = 1;
1641                 }
1642                 setProcessPriority(priority);
1643 #endif
1644 
1645                 /* options for ID3 tag */
1646 #ifdef ID3TAGS_EXTENDED
1647                 T_ELIF2("id3v2-utf16","id3v2-ucs2") /* id3v2-ucs2 for compatibility only */
1648                     id3_tenc = TENC_UTF16;
1649                     id3tag_add_v2(gfp);
1650 
1651                 T_ELIF("id3v2-latin1")
1652                     id3_tenc = TENC_LATIN1;
1653                     id3tag_add_v2(gfp);
1654 #endif
1655 
1656                 T_ELIF("tt")
1657                     argUsed = 1;
1658                     id3_tag(gfp, 't', id3_tenc, nextArg);
1659 
1660                 T_ELIF("ta")
1661                     argUsed = 1;
1662                     id3_tag(gfp, 'a', id3_tenc, nextArg);
1663 
1664                 T_ELIF("tl")
1665                     argUsed = 1;
1666                     id3_tag(gfp, 'l', id3_tenc, nextArg);
1667 
1668                 T_ELIF("ty")
1669                     argUsed = 1;
1670                     id3_tag(gfp, 'y', id3_tenc, nextArg);
1671 
1672                 T_ELIF("tc")
1673                     argUsed = 1;
1674                     id3_tag(gfp, 'c', id3_tenc, nextArg);
1675 
1676                 T_ELIF("tn")
1677                     int ret = id3_tag(gfp, 'n', id3_tenc, nextArg);
1678                     argUsed = 1;
1679                     if (ret != 0) {
1680                         if (0 == ignore_tag_errors) {
1681                             if (id3tag_mode == ID3TAG_MODE_V1_ONLY) {
1682                                 if (global_ui_config.silent < 9) {
1683                                     error_printf("The track number has to be between 1 and 255 for ID3v1.\n");
1684                                 }
1685                                 return -1;
1686                             }
1687                             else if (id3tag_mode == ID3TAG_MODE_V2_ONLY) {
1688                                 /* track will be stored as-is in ID3v2 case, so no problem here */
1689                             }
1690                             else {
1691                                 if (global_ui_config.silent < 9) {
1692                                     error_printf("The track number has to be between 1 and 255 for ID3v1, ignored for ID3v1.\n");
1693                                 }
1694                             }
1695                         }
1696                     }
1697 
1698                 T_ELIF("tg")
1699                     int ret = id3_tag(gfp, 'g', id3_tenc, nextArg);
1700                     argUsed = 1;
1701                     if (ret != 0) {
1702                         if (0 == ignore_tag_errors) {
1703                             if (ret == -1) {
1704                                 error_printf("Unknown ID3v1 genre number: '%s'.\n", nextArg);
1705                                 return -1;
1706                             }
1707                             else if (ret == -2) {
1708                                 if (id3tag_mode == ID3TAG_MODE_V1_ONLY) {
1709                                     error_printf("Unknown ID3v1 genre: '%s'.\n", nextArg);
1710                                     return -1;
1711                                 }
1712                                 else if (id3tag_mode == ID3TAG_MODE_V2_ONLY) {
1713                                     /* genre will be stored as-is in ID3v2 case, so no problem here */
1714                                 }
1715                                 else {
1716                                     if (global_ui_config.silent < 9) {
1717                                         error_printf("Unknown ID3v1 genre: '%s'.  Setting ID3v1 genre to 'Other'\n", nextArg);
1718                                     }
1719                                 }
1720                             }
1721                             else {
1722                                 if (global_ui_config.silent < 10)
1723                                     error_printf("Internal error.\n");
1724                                 return -1;
1725                             }
1726                         }
1727                     }
1728 
1729                 T_ELIF("tv")
1730                     argUsed = 1;
1731                     if (id3_tag(gfp, 'v', id3_tenc, nextArg)) {
1732                         if (global_ui_config.silent < 9) {
1733                             error_printf("Invalid field value: '%s'. Ignored\n", nextArg);
1734                         }
1735                     }
1736 
1737                 T_ELIF("ti")
1738                     argUsed = 1;
1739                     if (set_id3_albumart(gfp, nextArg) != 0) {
1740                         if (! ignore_tag_errors) {
1741                             return -1;
1742                         }
1743                     }
1744 
1745                 T_ELIF("ignore-tag-errors")
1746                     ignore_tag_errors = 1;
1747 
1748                 T_ELIF("add-id3v2")
1749                     id3tag_add_v2(gfp);
1750 
1751                 T_ELIF("id3v1-only")
1752                     id3tag_v1_only(gfp);
1753                     id3tag_mode = ID3TAG_MODE_V1_ONLY;
1754 
1755                 T_ELIF("id3v2-only")
1756                     id3tag_v2_only(gfp);
1757                     id3tag_mode = ID3TAG_MODE_V2_ONLY;
1758 
1759                 T_ELIF("space-id3v1")
1760                     id3tag_space_v1(gfp);
1761 
1762                 T_ELIF("pad-id3v2")
1763                     id3tag_pad_v2(gfp);
1764 
1765                 T_ELIF("pad-id3v2-size")
1766                     int n = atoi(nextArg);
1767                     n = n <= 128000 ? n : 128000;
1768                     n = n >= 0      ? n : 0;
1769                     id3tag_set_pad(gfp, n);
1770                     argUsed = 1;
1771 
1772 
1773                 T_ELIF("genre-list")
1774                     id3tag_genre_list(genre_list_handler, NULL);
1775                     return -2;
1776 
1777 
1778                 T_ELIF("lowpass")
1779                     val = atof(nextArg);
1780                 argUsed = 1;
1781                 if (val < 0) {
1782                     lame_set_lowpassfreq(gfp, -1);
1783                 }
1784                 else {
1785                     /* useful are 0.001 kHz...50 kHz, 50 Hz...50000 Hz */
1786                     if (val < 0.001 || val > 50000.) {
1787                         error_printf("Must specify lowpass with --lowpass freq, freq >= 0.001 kHz\n");
1788                         return -1;
1789                     }
1790                     lame_set_lowpassfreq(gfp, (int) (val * (val < 50. ? 1.e3 : 1.e0) + 0.5));
1791                 }
1792 
1793                 T_ELIF("lowpass-width")
1794                     val = atof(nextArg);
1795                 argUsed = 1;
1796                 /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1797                 if (val < 0.001 || val > 50000.) {
1798                     error_printf
1799                         ("Must specify lowpass width with --lowpass-width freq, freq >= 0.001 kHz\n");
1800                     return -1;
1801                 }
1802                 lame_set_lowpasswidth(gfp, (int) (val * (val < 16. ? 1.e3 : 1.e0) + 0.5));
1803 
1804                 T_ELIF("highpass")
1805                     val = atof(nextArg);
1806                 argUsed = 1;
1807                 if (val < 0.0) {
1808                     lame_set_highpassfreq(gfp, -1);
1809                 }
1810                 else {
1811                     /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1812                     if (val < 0.001 || val > 50000.) {
1813                         error_printf("Must specify highpass with --highpass freq, freq >= 0.001 kHz\n");
1814                         return -1;
1815                     }
1816                     lame_set_highpassfreq(gfp, (int) (val * (val < 16. ? 1.e3 : 1.e0) + 0.5));
1817                 }
1818 
1819                 T_ELIF("highpass-width")
1820                     val = atof(nextArg);
1821                 argUsed = 1;
1822                 /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1823                 if (val < 0.001 || val > 50000.) {
1824                     error_printf
1825                         ("Must specify highpass width with --highpass-width freq, freq >= 0.001 kHz\n");
1826                     return -1;
1827                 }
1828                 lame_set_highpasswidth(gfp, (int) val);
1829 
1830                 T_ELIF("comp")
1831                     argUsed = 1;
1832                 val = atof(nextArg);
1833                 if (val < 1.0) {
1834                     error_printf("Must specify compression ratio >= 1.0\n");
1835                     return -1;
1836                 }
1837                 lame_set_compression_ratio(gfp, (float) val);
1838 #if INTERNAL_OPTS
1839                 T_ELIF_INTERNAL("notemp")
1840                     (void) lame_set_useTemporal(gfp, 0);
1841 
1842                 T_ELIF_INTERNAL("interch")
1843                     argUsed = 1;
1844                 (void) lame_set_interChRatio(gfp, (float) atof(nextArg));
1845 
1846                 T_ELIF_INTERNAL("temporal-masking")
1847                     argUsed = 1;
1848                 (void) lame_set_useTemporal(gfp, atoi(nextArg) ? 1 : 0);
1849 
1850                 T_ELIF_INTERNAL("nspsytune")
1851                     ;
1852 
1853                 T_ELIF_INTERNAL("nssafejoint")
1854                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2);
1855 
1856                 T_ELIF_INTERNAL("nsmsfix")
1857                     argUsed = 1;
1858                 (void) lame_set_msfix(gfp, atof(nextArg));
1859 
1860                 T_ELIF_INTERNAL("ns-bass")
1861                     argUsed = 1;
1862                 {
1863                     double  d;
1864                     int     k;
1865                     d = atof(nextArg);
1866                     k = (int) (d * 4);
1867                     if (k < -32)
1868                         k = -32;
1869                     if (k > 31)
1870                         k = 31;
1871                     if (k < 0)
1872                         k += 64;
1873                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 2));
1874                 }
1875 
1876                 T_ELIF_INTERNAL("ns-alto")
1877                     argUsed = 1;
1878                 {
1879                     double  d;
1880                     int     k;
1881                     d = atof(nextArg);
1882                     k = (int) (d * 4);
1883                     if (k < -32)
1884                         k = -32;
1885                     if (k > 31)
1886                         k = 31;
1887                     if (k < 0)
1888                         k += 64;
1889                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 8));
1890                 }
1891 
1892                 T_ELIF_INTERNAL("ns-treble")
1893                     argUsed = 1;
1894                 {
1895                     double  d;
1896                     int     k;
1897                     d = atof(nextArg);
1898                     k = (int) (d * 4);
1899                     if (k < -32)
1900                         k = -32;
1901                     if (k > 31)
1902                         k = 31;
1903                     if (k < 0)
1904                         k += 64;
1905                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 14));
1906                 }
1907 
1908                 T_ELIF_INTERNAL("ns-sfb21")
1909                     /*  to be compatible with Naoki's original code,
1910                      *  ns-sfb21 specifies how to change ns-treble for sfb21 */
1911                     argUsed = 1;
1912                 {
1913                     double  d;
1914                     int     k;
1915                     d = atof(nextArg);
1916                     k = (int) (d * 4);
1917                     if (k < -32)
1918                         k = -32;
1919                     if (k > 31)
1920                         k = 31;
1921                     if (k < 0)
1922                         k += 64;
1923                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 20));
1924                 }
1925 #endif
1926                 /* some more GNU-ish options could be added
1927                  * brief         => few messages on screen (name, status report)
1928                  * o/output file => specifies output filename
1929                  * O             => stdout
1930                  * i/input file  => specifies input filename
1931                  * I             => stdin
1932                  */
1933                 T_ELIF("quiet")
1934                     global_ui_config.silent = 10; /* on a scale from 1 to 10 be very silent */
1935 
1936                 T_ELIF("silent")
1937                     global_ui_config.silent = 9;
1938 
1939                 T_ELIF("brief")
1940                     global_ui_config.silent = -5; /* print few info on screen */
1941 
1942                 T_ELIF("verbose")
1943                     global_ui_config.silent = -10; /* print a lot on screen */
1944 
1945                 T_ELIF2("version", "license")
1946                     print_license(stdout);
1947                 return -2;
1948 
1949                 T_ELIF2("help", "usage")
1950                     if (0 == local_strncasecmp(nextArg, "id3", 3)) {
1951                         help_id3tag(stdout);
1952                     }
1953                     else if (0 == local_strncasecmp(nextArg, "dev", 3)) {
1954                         help_developer_switches(stdout);
1955                     }
1956                     else {
1957                         short_help(gfp, stdout, ProgramName);
1958                     }
1959                 return -2;
1960 
1961                 T_ELIF("longhelp")
1962                     long_help(gfp, stdout, ProgramName, 0 /* lessmode=NO */ );
1963                 return -2;
1964 
1965                 T_ELIF("?")
1966 #ifdef __unix__
1967                     FILE   *fp = popen("less -Mqc", "w");
1968                     long_help(gfp, fp, ProgramName, 0 /* lessmode=NO */ );
1969                     pclose(fp);
1970 #else
1971                     long_help(gfp, stdout, ProgramName, 1 /* lessmode=YES */ );
1972 #endif
1973                 return -2;
1974 
1975                 T_ELIF2("preset", "alt-preset")
1976                     argUsed = 1;
1977                 {
1978                     int     fast = 0, cbr = 0;
1979 
1980                     while ((strcmp(nextArg, "fast") == 0) || (strcmp(nextArg, "cbr") == 0)) {
1981 
1982                         if ((strcmp(nextArg, "fast") == 0) && (fast < 1))
1983                             fast = 1;
1984                         if ((strcmp(nextArg, "cbr") == 0) && (cbr < 1))
1985                             cbr = 1;
1986 
1987                         argUsed++;
1988                         nextArg = i + argUsed < argc ? argv[i + argUsed] : "";
1989                     }
1990 
1991                     if (presets_set(gfp, fast, cbr, nextArg, ProgramName) < 0)
1992                         return -1;
1993                 }
1994 
1995                 T_ELIF("disptime")
1996                     argUsed = 1;
1997                     global_ui_config.update_interval = (float) atof(nextArg);
1998 
1999                 T_ELIF("nogaptags")
2000                     nogap_tags = 1;
2001 
2002                 T_ELIF("nogapout")
2003                     /* FIXME: replace strcpy by safer strncpy */
2004                     strcpy(outPath, nextArg);
2005                 argUsed = 1;
2006 
2007                 T_ELIF("out-dir")
2008                     /* FIXME: replace strcpy by safer strncpy */
2009                     strcpy(outDir, nextArg);
2010                 argUsed = 1;
2011 
2012                 T_ELIF("nogap")
2013                     nogap = 1;
2014 
2015                 T_ELIF("swap-channel")
2016                     global_reader.swap_channel = 1;
2017 #if INTERNAL_OPTS
2018                 T_ELIF_INTERNAL("tune") /*without helptext */
2019                     argUsed = 1;
2020                     lame_set_tune(gfp, (float) atof(nextArg));
2021 
2022                 T_ELIF_INTERNAL("shortthreshold") {
2023                     float   x, y;
2024                     int     n = sscanf(nextArg, "%f,%f", &x, &y);
2025                     if (n == 1) {
2026                         y = x;
2027                     }
2028                     argUsed = 1;
2029                     (void) lame_set_short_threshold(gfp, x, y);
2030                 }
2031 
2032                 T_ELIF_INTERNAL("maskingadjust") /*without helptext */
2033                     argUsed = 1;
2034                 (void) lame_set_maskingadjust(gfp, (float) atof(nextArg));
2035 
2036                 T_ELIF_INTERNAL("maskingadjustshort") /*without helptext */
2037                     argUsed = 1;
2038                 (void) lame_set_maskingadjust_short(gfp, (float) atof(nextArg));
2039 
2040                 T_ELIF_INTERNAL("athcurve") /*without helptext */
2041                     argUsed = 1;
2042                 (void) lame_set_ATHcurve(gfp, (float) atof(nextArg));
2043 
2044                 T_ELIF_INTERNAL("no-preset-tune") /*without helptext */
2045                     (void) lame_set_preset_notune(gfp, 0);
2046 
2047                 T_ELIF_INTERNAL("substep")
2048                     argUsed = 1;
2049                 (void) lame_set_substep(gfp, atoi(nextArg));
2050 
2051                 T_ELIF_INTERNAL("sbgain") /*without helptext */
2052                     argUsed = 1;
2053                 (void) lame_set_subblock_gain(gfp, atoi(nextArg));
2054 
2055                 T_ELIF_INTERNAL("sfscale") /*without helptext */
2056                     (void) lame_set_sfscale(gfp, 1);
2057 
2058                 T_ELIF_INTERNAL("noath")
2059                     (void) lame_set_noATH(gfp, 1);
2060 
2061                 T_ELIF_INTERNAL("athonly")
2062                     (void) lame_set_ATHonly(gfp, 1);
2063 
2064                 T_ELIF_INTERNAL("athshort")
2065                     (void) lame_set_ATHshort(gfp, 1);
2066 
2067                 T_ELIF_INTERNAL("athlower")
2068                     argUsed = 1;
2069                 (void) lame_set_ATHlower(gfp, (float) atof(nextArg));
2070 
2071                 T_ELIF_INTERNAL("athtype")
2072                     argUsed = 1;
2073                 (void) lame_set_ATHtype(gfp, atoi(nextArg));
2074 
2075                 T_ELIF_INTERNAL("athaa-type") /*  switch for developing, no DOCU */
2076                     argUsed = 1; /* once was 1:Gaby, 2:Robert, 3:Jon, else:off */
2077                 lame_set_athaa_type(gfp, atoi(nextArg)); /* now: 0:off else:Jon */
2078 #endif
2079                 T_ELIF ("athaa-sensitivity")
2080                     argUsed=1;
2081                 lame_set_athaa_sensitivity(gfp, (float) atof(nextArg));
2082 
2083                 T_ELIF_INTERNAL("debug-file") /* switch for developing, no DOCU */
2084                     argUsed = 1; /* file name to print debug info into */
2085                 {
2086                     set_debug_file(nextArg);
2087                 }
2088 
2089                 T_ELSE {
2090                     error_printf("%s: unrecognized option --%s\n", ProgramName, token);
2091                     return -1;
2092                 }
2093                 T_END   i += argUsed;
2094 
2095             }
2096             else {
2097                 while ((c = *token++) != '\0') {
2098                     arg = *token ? token : nextArg;
2099                     switch (c) {
2100                     case 'm':
2101                         argUsed = 1;
2102 
2103                         switch (*arg) {
2104                         case 's':
2105                             (void) lame_set_mode(gfp, STEREO);
2106                             break;
2107                         case 'd':
2108                             (void) lame_set_mode(gfp, DUAL_CHANNEL);
2109                             break;
2110                         case 'f':
2111                             lame_set_force_ms(gfp, 1);
2112                             /* FALLTHROUGH */
2113                         case 'j':
2114                             (void) lame_set_mode(gfp, JOINT_STEREO);
2115                             break;
2116                         case 'm':
2117                             (void) lame_set_mode(gfp, MONO);
2118                             break;
2119                         case 'l':
2120                             (void) lame_set_mode(gfp, MONO);
2121                             (void) lame_set_scale_left(gfp, 2);
2122                             (void) lame_set_scale_right(gfp, 0);
2123                             break;
2124                         case 'r':
2125                             (void) lame_set_mode(gfp, MONO);
2126                             (void) lame_set_scale_left(gfp, 0);
2127                             (void) lame_set_scale_right(gfp, 2);
2128                             break;
2129                         case 'a':
2130                             (void) lame_set_mode(gfp, JOINT_STEREO);
2131                             break;
2132                         default:
2133                             error_printf("%s: -m mode must be s/d/j/f/m not %s\n", ProgramName,
2134                                          arg);
2135                             return -1;
2136                         }
2137                         break;
2138 
2139                     case 'V':
2140                         argUsed = 1;
2141                         /* to change VBR default look in lame.h */
2142                         if (lame_get_VBR(gfp) == vbr_off)
2143                             lame_set_VBR(gfp, vbr_default);
2144                         lame_set_VBR_quality(gfp, (float)atof(arg));
2145                         break;
2146                     case 'v':
2147                         /* to change VBR default look in lame.h */
2148                         if (lame_get_VBR(gfp) == vbr_off)
2149                             lame_set_VBR(gfp, vbr_default);
2150                         break;
2151 
2152                     case 'q':
2153                         argUsed = 1;
2154                         (void) lame_set_quality(gfp, atoi(arg));
2155                         break;
2156                     case 'f':
2157                         (void) lame_set_quality(gfp, 7);
2158                         break;
2159                     case 'h':
2160                         (void) lame_set_quality(gfp, 2);
2161                         break;
2162 
2163                     case 's':
2164                         argUsed = 1;
2165                         val = atof(arg);
2166                         val = (int) (val * (val <= 192 ? 1.e3 : 1.e0) + 0.5);
2167                         global_reader.input_samplerate = (int)val;
2168                         (void) lame_set_in_samplerate(gfp, (int)val);
2169                         break;
2170                     case 'b':
2171                         argUsed = 1;
2172                         lame_set_brate(gfp, atoi(arg));
2173                         lame_set_VBR_min_bitrate_kbps(gfp, lame_get_brate(gfp));
2174                         break;
2175                     case 'B':
2176                         argUsed = 1;
2177                         lame_set_VBR_max_bitrate_kbps(gfp, atoi(arg));
2178                         break;
2179                     case 'F':
2180                         lame_set_VBR_hard_min(gfp, 1);
2181                         break;
2182                     case 't': /* dont write VBR tag */
2183                         (void) lame_set_bWriteVbrTag(gfp, 0);
2184                         global_decoder.disable_wav_header = 1;
2185                         break;
2186                     case 'T': /* do write VBR tag */
2187                         (void) lame_set_bWriteVbrTag(gfp, 1);
2188                         nogap_tags = 1;
2189                         global_decoder.disable_wav_header = 0;
2190                         break;
2191                     case 'r': /* force raw pcm input file */
2192 #if defined(LIBSNDFILE)
2193                         error_printf
2194                             ("WARNING: libsndfile may ignore -r and perform fseek's on the input.\n"
2195                              "Compile without libsndfile if this is a problem.\n");
2196 #endif
2197                         global_reader.input_format = sf_raw;
2198                         break;
2199                     case 'x': /* force byte swapping */
2200                         global_reader.swapbytes = 1;
2201                         break;
2202                     case 'p': /* (jo) error_protection: add crc16 information to stream */
2203                         lame_set_error_protection(gfp, 1);
2204                         break;
2205                     case 'a': /* autoconvert input file from stereo to mono - for mono mp3 encoding */
2206                         autoconvert = 1;
2207                         (void) lame_set_mode(gfp, MONO);
2208                         break;
2209                     case 'd':   /*(void) lame_set_allow_diff_short( gfp, 1 ); */
2210                     case 'k':   /*lame_set_lowpassfreq(gfp, -1);
2211                                   lame_set_highpassfreq(gfp, -1); */
2212                         error_printf("WARNING: -%c is obsolete.\n", c);
2213                         break;
2214                     case 'S':
2215                         global_ui_config.silent = 5;
2216                         break;
2217                     case 'X':
2218                         /*  experimental switch -X:
2219                             the differnt types of quant compare are tough
2220                             to communicate to endusers, so they shouldn't
2221                             bother to toy around with them
2222                          */
2223                         {
2224                             int     x, y;
2225                             int     n = sscanf(arg, "%d,%d", &x, &y);
2226                             if (n == 1) {
2227                                 y = x;
2228                             }
2229                             argUsed = 1;
2230                             if (internal_opts_enabled) {
2231                                 lame_set_quant_comp(gfp, x);
2232                                 lame_set_quant_comp_short(gfp, y);
2233                             }
2234                         }
2235                         break;
2236                     case 'Y':
2237                         lame_set_experimentalY(gfp, 1);
2238                         break;
2239                     case 'Z':
2240                         /*  experimental switch -Z:
2241                          */
2242                         {
2243                             int     n = 1;
2244                             argUsed = sscanf(arg, "%d", &n);
2245                             /*if (internal_opts_enabled)*/
2246                             {
2247                                 lame_set_experimentalZ(gfp, n);
2248                             }
2249                         }
2250                         break;
2251                     case 'e':
2252                         argUsed = 1;
2253 
2254                         switch (*arg) {
2255                         case 'n':
2256                             lame_set_emphasis(gfp, 0);
2257                             break;
2258                         case '5':
2259                             lame_set_emphasis(gfp, 1);
2260                             break;
2261                         case 'c':
2262                             lame_set_emphasis(gfp, 3);
2263                             break;
2264                         default:
2265                             error_printf("%s: -e emp must be n/5/c not %s\n", ProgramName, arg);
2266                             return -1;
2267                         }
2268                         break;
2269                     case 'c':
2270                         lame_set_copyright(gfp, 1);
2271                         break;
2272                     case 'o':
2273                         lame_set_original(gfp, 0);
2274                         break;
2275 
2276                     case '?':
2277                         long_help(gfp, stdout, ProgramName, 0 /* LESSMODE=NO */ );
2278                         return -1;
2279 
2280                     default:
2281                         error_printf("%s: unrecognized option -%c\n", ProgramName, c);
2282                         return -1;
2283                     }
2284                     if (argUsed) {
2285                         if (arg == token)
2286                             token = ""; /* no more from token */
2287                         else
2288                             ++i; /* skip arg we used */
2289                         arg = "";
2290                         argUsed = 0;
2291                     }
2292                 }
2293             }
2294         }
2295         else {
2296             if (nogap) {
2297                 if ((num_nogap != NULL) && (count_nogap < *num_nogap)) {
2298                     strncpy(nogap_inPath[count_nogap++], argv[i], PATH_MAX + 1);
2299                     input_file = 1;
2300                 }
2301                 else {
2302                     /* sorry, calling program did not allocate enough space */
2303                     error_printf
2304                         ("Error: 'nogap option'.  Calling program does not allow nogap option, or\n"
2305                          "you have exceeded maximum number of input files for the nogap option\n");
2306                     *num_nogap = -1;
2307                     return -1;
2308                 }
2309             }
2310             else {
2311                 /* normal options:   inputfile  [outputfile], and
2312                    either one can be a '-' for stdin/stdout */
2313                 if (inPath[0] == '\0') {
2314                     strncpy(inPath, argv[i], PATH_MAX + 1);
2315                     input_file = 1;
2316                 }
2317                 else {
2318                     if (outPath[0] == '\0')
2319                         strncpy(outPath, argv[i], PATH_MAX + 1);
2320                     else {
2321                         error_printf("%s: excess arg %s\n", ProgramName, argv[i]);
2322                         return -1;
2323                     }
2324                 }
2325             }
2326         }
2327     }                   /* loop over args */
2328 
2329     if (!input_file) {
2330         usage(Console_IO.Console_fp, ProgramName);
2331         return -1;
2332     }
2333 
2334     if (inPath[0] == '-')
2335         global_ui_config.silent = (global_ui_config.silent <= 1 ? 1 : global_ui_config.silent);
2336 #ifdef WIN32
2337     else
2338         dosToLongFileName(inPath);
2339 #endif
2340 
2341     if (outPath[0] == '\0' && count_nogap == 0) {
2342         if (inPath[0] == '-') {
2343             /* if input is stdin, default output is stdout */
2344             strcpy(outPath, "-");
2345         }
2346         else {
2347             if (generateOutPath(gfp, inPath, outDir, outPath) != 0) {
2348                 return -1;
2349             }
2350         }
2351     }
2352 
2353     /* RG is enabled by default */
2354     if (!noreplaygain)
2355         lame_set_findReplayGain(gfp, 1);
2356 
2357     /* disable VBR tags with nogap unless the VBR tags are forced */
2358     if (nogap && lame_get_bWriteVbrTag(gfp) && nogap_tags == 0) {
2359         console_printf("Note: Disabling VBR Xing/Info tag since it interferes with --nogap\n");
2360         lame_set_bWriteVbrTag(gfp, 0);
2361     }
2362 
2363     /* some file options not allowed with stdout */
2364     if (outPath[0] == '-') {
2365         (void) lame_set_bWriteVbrTag(gfp, 0); /* turn off VBR tag */
2366     }
2367 
2368     /* if user did not explicitly specify input is mp3, check file name */
2369     if (global_reader.input_format == sf_unknown)
2370         global_reader.input_format = filename_to_type(inPath);
2371 
2372 #if !(defined HAVE_MPGLIB || defined AMIGA_MPEGA)
2373     if (is_mpeg_file_format(global_reader.input_format)) {
2374         error_printf("Error: libmp3lame not compiled with mpg123 *decoding* support \n");
2375         return -1;
2376     }
2377 #endif
2378 
2379     /* default guess for number of channels */
2380     if (autoconvert)
2381         (void) lame_set_num_channels(gfp, 2);
2382     else if (MONO == lame_get_mode(gfp))
2383         (void) lame_set_num_channels(gfp, 1);
2384     else
2385         (void) lame_set_num_channels(gfp, 2);
2386 
2387     if (lame_get_free_format(gfp)) {
2388         if (lame_get_brate(gfp) < 8 || lame_get_brate(gfp) > 640) {
2389             error_printf("For free format, specify a bitrate between 8 and 640 kbps\n");
2390             error_printf("with the -b <bitrate> option\n");
2391             return -1;
2392         }
2393     }
2394     if (num_nogap != NULL)
2395         *num_nogap = count_nogap;
2396     return 0;
2397 }
2398 
2399 
2400 /* end of parse.c */
2401