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