00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #include <assert.h>
00030 #include <stdio.h>
00031
00032 #ifdef STDC_HEADERS
00033 # include <stdlib.h>
00034 # include <string.h>
00035 #else
00036 # ifndef HAVE_STRCHR
00037 # define strchr index
00038 # define strrchr rindex
00039 # endif
00040 char *strchr(), *strrchr();
00041 # ifndef HAVE_MEMCPY
00042 # define memcpy(d, s, n) bcopy ((s), (d), (n))
00043 # define memmove(d, s, n) bcopy ((s), (d), (n))
00044 # endif
00045 #endif
00046
00047 #ifdef HAVE_FCNTL_H
00048 # include <fcntl.h>
00049 #endif
00050
00051 #ifdef __sun__
00052
00053 #include <unistd.h>
00054 #endif
00055
00056 #if defined(_WIN32)
00057 # include <windows.h>
00058 #endif
00059
00060
00061
00062
00063
00064
00065
00066 #include "lame.h"
00067
00068 #include "console.h"
00069 #include "brhist.h"
00070 #include "parse.h"
00071 #include "main.h"
00072 #include "get_audio.h"
00073 #include "portableio.h"
00074 #include "timestatus.h"
00075
00076
00077 #if macintosh
00078 #include <console.h>
00079 #endif
00080
00081 #ifdef WITH_DMALLOC
00082 #include <dmalloc.h>
00083 #endif
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 static int
00098 parse_args_from_string(lame_global_flags * const gfp, const char *p, char *inPath, char *outPath)
00099 {
00100 char *q;
00101 char *f;
00102 char *r[128];
00103 int c = 0;
00104 int ret;
00105
00106 if (p == NULL || *p == '\0')
00107 return 0;
00108
00109 f = q = malloc(strlen(p) + 1);
00110 strcpy(q, p);
00111
00112 r[c++] = "lhama";
00113 while (1) {
00114 r[c++] = q;
00115 while (*q != ' ' && *q != '\0')
00116 q++;
00117 if (*q == '\0')
00118 break;
00119 *q++ = '\0';
00120 }
00121 r[c] = NULL;
00122
00123 ret = parse_args(gfp, c, r, inPath, outPath, NULL, NULL);
00124 free(f);
00125 return ret;
00126 }
00127
00128
00129
00130
00131
00132 static FILE *
00133 init_files(lame_global_flags * gf, char *inPath, char *outPath, int *enc_delay, int *enc_padding)
00134 {
00135 FILE *outf;
00136
00137
00138
00139
00140 if (0 != strcmp("-", outPath) && 0 == strcmp(inPath, outPath)) {
00141 error_printf("Input file and Output file are the same. Abort.\n");
00142 return NULL;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 init_infile(gf, inPath, enc_delay, enc_padding);
00152 if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
00153 error_printf("Can't init outfile '%s'\n", outPath);
00154 return NULL;
00155 }
00156
00157 return outf;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 int
00174 lame_decoder(lame_global_flags * gfp, FILE * outf, int skip_start, char *inPath, char *outPath,
00175 int *enc_delay, int *enc_padding)
00176 {
00177 short int Buffer[2][1152];
00178 int iread;
00179 int skip_end = 0;
00180 double wavsize;
00181 int i;
00182 void (*WriteFunction) (FILE * fp, char *p, int n);
00183 int tmp_num_channels = lame_get_num_channels(gfp);
00184
00185
00186
00187 if (silent < 10)
00188 console_printf("\rinput: %s%s(%g kHz, %i channel%s, ",
00189 strcmp(inPath, "-") ? inPath : "<stdin>",
00190 strlen(inPath) > 26 ? "\n\t" : " ",
00191 lame_get_in_samplerate(gfp) / 1.e3,
00192 tmp_num_channels, tmp_num_channels != 1 ? "s" : "");
00193
00194 switch (input_format) {
00195 case sf_mp123:
00196 error_printf("Internal error. Aborting.");
00197 exit(-1);
00198
00199 case sf_mp3:
00200 if (skip_start == 0) {
00201 if (*enc_delay > -1 || *enc_padding > -1) {
00202 if (*enc_delay > -1)
00203 skip_start = *enc_delay + 528 + 1;
00204 if (*enc_padding > -1)
00205 skip_end = *enc_padding - (528 + 1);
00206 }
00207 else
00208 skip_start = lame_get_encoder_delay(gfp) + 528 + 1;
00209 }
00210 else {
00211
00212 skip_start += 528 + 1;
00213 }
00214
00215 if (silent < 10)
00216 console_printf("MPEG-%u%s Layer %s", 2 - lame_get_version(gfp),
00217 lame_get_out_samplerate(gfp) < 16000 ? ".5" : "", "III");
00218 break;
00219 case sf_mp2:
00220 skip_start += 240 + 1;
00221 if (silent < 10)
00222 console_printf("MPEG-%u%s Layer %s", 2 - lame_get_version(gfp),
00223 lame_get_out_samplerate(gfp) < 16000 ? ".5" : "", "II");
00224 break;
00225 case sf_mp1:
00226 skip_start += 240 + 1;
00227 if (silent < 10)
00228 console_printf("MPEG-%u%s Layer %s", 2 - lame_get_version(gfp),
00229 lame_get_out_samplerate(gfp) < 16000 ? ".5" : "", "I");
00230 break;
00231 case sf_raw:
00232 if (silent < 10)
00233 console_printf("raw PCM data");
00234 mp3input_data.nsamp = lame_get_num_samples(gfp);
00235 mp3input_data.framesize = 1152;
00236 skip_start = 0;
00237 break;
00238 case sf_wave:
00239 if (silent < 10)
00240 console_printf("Microsoft WAVE");
00241 mp3input_data.nsamp = lame_get_num_samples(gfp);
00242 mp3input_data.framesize = 1152;
00243 skip_start = 0;
00244 break;
00245 case sf_aiff:
00246 if (silent < 10)
00247 console_printf("SGI/Apple AIFF");
00248 mp3input_data.nsamp = lame_get_num_samples(gfp);
00249 mp3input_data.framesize = 1152;
00250 skip_start = 0;
00251 break;
00252 default:
00253 if (silent < 10)
00254 console_printf("unknown");
00255 mp3input_data.nsamp = lame_get_num_samples(gfp);
00256 mp3input_data.framesize = 1152;
00257 skip_start = 0;
00258 assert(0);
00259 break;
00260 }
00261
00262 if (silent < 10) {
00263 console_printf(")\noutput: %s%s(16 bit, Microsoft WAVE)\n",
00264 strcmp(outPath, "-") ? outPath : "<stdout>",
00265 strlen(outPath) > 45 ? "\n\t" : " ");
00266
00267 if (skip_start > 0)
00268 console_printf("skipping initial %i samples (encoder+decoder delay)\n", skip_start);
00269 if (skip_end > 0)
00270 console_printf("skipping final %i samples (encoder padding-decoder delay)\n", skip_end);
00271 }
00272
00273 if (0 == disable_wav_header)
00274 WriteWaveHeader(outf, 0x7FFFFFFF, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
00275
00276
00277 wavsize = -(skip_start + skip_end);
00278 WriteFunction = swapbytes ? WriteBytesSwapped : WriteBytes;
00279 mp3input_data.totalframes = mp3input_data.nsamp / mp3input_data.framesize;
00280
00281 assert(tmp_num_channels >= 1 && tmp_num_channels <= 2);
00282
00283 do {
00284 iread = get_audio16(gfp, Buffer);
00285 if (iread >= 0) {
00286 mp3input_data.framenum += iread / mp3input_data.framesize;
00287 wavsize += iread;
00288
00289 if (silent <= 0) {
00290 decoder_progress(&mp3input_data);
00291 console_flush();
00292 }
00293
00294 skip_start -= (i = skip_start < iread ? skip_start : iread);
00295
00296 if (skip_end > 1152 && mp3input_data.framenum + 2 > mp3input_data.totalframes) {
00297 iread -= (skip_end - 1152);
00298 skip_end = 1152;
00299 }
00300 else if (mp3input_data.framenum == mp3input_data.totalframes && iread != 0)
00301 iread -= skip_end;
00302
00303 for (; i < iread; i++) {
00304 if (disable_wav_header) {
00305 WriteFunction(outf, (char *) &Buffer[0][i], sizeof(short));
00306 if (tmp_num_channels == 2)
00307 WriteFunction(outf, (char *) &Buffer[1][i], sizeof(short));
00308 }
00309 else {
00310 Write16BitsLowHigh(outf, Buffer[0][i]);
00311 if (tmp_num_channels == 2)
00312 Write16BitsLowHigh(outf, Buffer[1][i]);
00313 }
00314 }
00315 if (flush_write == 1) {
00316 fflush(outf);
00317 }
00318 }
00319 } while (iread > 0);
00320
00321 i = (16 / 8) * tmp_num_channels;
00322 assert(i > 0);
00323 if (wavsize <= 0) {
00324 if (silent < 10)
00325 error_printf("WAVE file contains 0 PCM samples\n");
00326 wavsize = 0;
00327 }
00328 else if (wavsize > 0xFFFFFFD0 / i) {
00329 if (silent < 10)
00330 error_printf("Very huge WAVE file, can't set filesize accordingly\n");
00331 wavsize = 0xFFFFFFD0;
00332 }
00333 else {
00334 wavsize *= i;
00335 }
00336
00337
00338 if (!disable_wav_header && strcmp("-", outPath)
00339 && !fseek(outf, 0l, SEEK_SET))
00340 WriteWaveHeader(outf, (int) wavsize, lame_get_in_samplerate(gfp),
00341 tmp_num_channels, 16);
00342 fclose(outf);
00343
00344 if (silent <= 0)
00345 decoder_progress_finish();
00346 return 0;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 static int
00361 lame_encoder(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
00362 {
00363 unsigned char mp3buffer[LAME_MAXMP3BUFFER];
00364 int Buffer[2][1152];
00365 int iread, imp3, owrite;
00366
00367 encoder_progress_begin(gf, inPath, outPath);
00368
00369
00370 do {
00371
00372 iread = get_audio(gf, Buffer);
00373
00374 if (iread >= 0) {
00375 encoder_progress(gf);
00376
00377
00378 imp3 = lame_encode_buffer_int(gf, Buffer[0], Buffer[1], iread,
00379 mp3buffer, sizeof(mp3buffer));
00380
00381
00382 if (imp3 < 0) {
00383 if (imp3 == -1)
00384 error_printf("mp3 buffer is not big enough... \n");
00385 else
00386 error_printf("mp3 internal error: error code=%i\n", imp3);
00387 return 1;
00388 }
00389 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
00390 if (owrite != imp3) {
00391 error_printf("Error writing mp3 output \n");
00392 return 1;
00393 }
00394 }
00395 if (flush_write == 1) {
00396 fflush(outf);
00397 }
00398 } while (iread > 0);
00399
00400 if (nogap)
00401 imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer));
00402 else
00403 imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer));
00404
00405 if (imp3 < 0) {
00406 if (imp3 == -1)
00407 error_printf("mp3 buffer is not big enough... \n");
00408 else
00409 error_printf("mp3 internal error: error code=%i\n", imp3);
00410 return 1;
00411
00412 }
00413
00414 encoder_progress_end(gf);
00415
00416 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
00417 if (owrite != imp3) {
00418 error_printf("Error writing mp3 output \n");
00419 return 1;
00420 }
00421 if (flush_write == 1) {
00422 fflush(outf);
00423 }
00424
00425 return 0;
00426 }
00427
00428
00429
00430
00431
00432
00433 static void
00434 brhist_init_package(lame_global_flags * gf)
00435 {
00436 #ifdef BRHIST
00437 if (brhist) {
00438 if (brhist_init(gf, lame_get_VBR_min_bitrate_kbps(gf), lame_get_VBR_max_bitrate_kbps(gf))) {
00439
00440 brhist = 0;
00441 }
00442 }
00443 else {
00444 brhist_init(gf, 128, 128);
00445 }
00446 #endif
00447 }
00448
00449
00450
00451 static
00452 void
00453 parse_nogap_filenames(int nogapout, char *inPath, char *outPath, char *outdir)
00454 {
00455
00456 char *slasher;
00457 size_t n;
00458
00459 strcpy(outPath, outdir);
00460 if (!nogapout) {
00461 strncpy(outPath, inPath, PATH_MAX + 1 - 4);
00462 n = strlen(outPath);
00463
00464 if (outPath[n - 3] == 'w'
00465 && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
00466 outPath[n - 3] = 'm';
00467 outPath[n - 2] = 'p';
00468 outPath[n - 1] = '3';
00469 }
00470 else {
00471 outPath[n + 0] = '.';
00472 outPath[n + 1] = 'm';
00473 outPath[n + 2] = 'p';
00474 outPath[n + 3] = '3';
00475 outPath[n + 4] = 0;
00476 }
00477 }
00478 else {
00479 slasher = inPath;
00480 slasher += PATH_MAX + 1 - 4;
00481
00482
00483 while (*slasher != '/' && *slasher != '\\' && slasher != inPath && *slasher != ':') {
00484 slasher--;
00485 }
00486
00487
00488 if (slasher != inPath
00489 && (outPath[strlen(outPath) - 1] == '/'
00490 || outPath[strlen(outPath) - 1] == '\\' || outPath[strlen(outPath) - 1] == ':'))
00491 slasher++;
00492 else if (slasher == inPath
00493 && (outPath[strlen(outPath) - 1] != '/'
00494 &&
00495 outPath[strlen(outPath) - 1] != '\\' && outPath[strlen(outPath) - 1] != ':'))
00496 #ifdef _WIN32
00497 strcat(outPath, "\\");
00498 #elif __OS2__
00499 strcat(outPath, "\\");
00500 #else
00501 strcat(outPath, "/");
00502 #endif
00503
00504 strncat(outPath, slasher, PATH_MAX + 1 - 4);
00505 n = strlen(outPath);
00506
00507 if (outPath[n - 3] == 'w'
00508 && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
00509 outPath[n - 3] = 'm';
00510 outPath[n - 2] = 'p';
00511 outPath[n - 1] = '3';
00512 }
00513 else {
00514 outPath[n + 0] = '.';
00515 outPath[n + 1] = 'm';
00516 outPath[n + 2] = 'p';
00517 outPath[n + 3] = '3';
00518 outPath[n + 4] = 0;
00519 }
00520 }
00521 }
00522
00523
00524
00525
00526 static void
00527 print_lame_tag_leading_info(lame_global_flags * gf)
00528 {
00529 if (lame_get_bWriteVbrTag(gf))
00530 console_printf("Writing LAME Tag...");
00531 }
00532
00533 static void
00534 print_trailing_info(lame_global_flags * gf)
00535 {
00536 if (lame_get_bWriteVbrTag(gf))
00537 console_printf("done\n");
00538
00539 if (lame_get_findReplayGain(gf)) {
00540 int RadioGain = lame_get_RadioGain(gf);
00541 console_printf("ReplayGain: %s%.1fdB\n", RadioGain > 0 ? "+" : "",
00542 ((float) RadioGain) / 10.0);
00543 if (RadioGain > 0x1FE || RadioGain < -0x1FE)
00544 error_printf
00545 ("WARNING: ReplayGain exceeds the -51dB to +51dB range. Such a result is too\n"
00546 " high to be stored in the header.\n");
00547 }
00548
00549
00550
00551 if (print_clipping_info && lame_get_decode_on_the_fly(gf)) {
00552 float noclipGainChange = (float) lame_get_noclipGainChange(gf) / 10.0f;
00553 float noclipScale = lame_get_noclipScale(gf);
00554
00555 if (noclipGainChange > 0.0) {
00556 console_printf
00557 ("WARNING: clipping occurs at the current gain. Set your decoder to decrease\n"
00558 " the gain by at least %.1fdB or encode again ", noclipGainChange);
00559
00560
00561 if (noclipScale > 0) {
00562 console_printf("using --scale %.2f\n", noclipScale);
00563 console_printf(" or less (the value under --scale is approximate).\n");
00564 }
00565 else {
00566
00567
00568
00569
00570 console_printf("using --scale <arg>\n"
00571 " (For a suggestion on the optimal value of <arg> encode\n"
00572 " with --scale 1 first)\n");
00573 }
00574
00575 }
00576 else {
00577 if (noclipGainChange > -0.1)
00578 console_printf
00579 ("\nThe waveform does not clip and is less than 0.1dB away from full scale.\n");
00580 else
00581 console_printf
00582 ("\nThe waveform does not clip and is at least %.1fdB away from full scale.\n",
00583 -noclipGainChange);
00584 }
00585 }
00586
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 int
00598 main(int argc, char **argv)
00599 {
00600 int ret;
00601 lame_global_flags *gf;
00602 char outPath[PATH_MAX + 1];
00603 char nogapdir[PATH_MAX + 1];
00604 char inPath[PATH_MAX + 1];
00605
00606
00607 int enc_delay = -1;
00608 int enc_padding = -1;
00609
00610
00611 #define MAX_NOGAP 200
00612 int nogapout = 0;
00613 int max_nogap = MAX_NOGAP;
00614 char *nogap_inPath[MAX_NOGAP];
00615
00616 int i;
00617 FILE *outf;
00618
00619 #if macintosh
00620 argc = ccommand(&argv);
00621 #endif
00622 #if 0
00623
00624
00625
00626
00627
00628 #if defined(_WIN32)
00629
00630
00631 typedef BOOL(WINAPI * SPAMFunc) (HANDLE, DWORD_PTR);
00632 SPAMFunc func;
00633 SYSTEM_INFO si;
00634
00635 if ((func = (SPAMFunc) GetProcAddress(GetModuleHandleW(L"KERNEL32.DLL"),
00636 "SetProcessAffinityMask")) != NULL) {
00637 GetSystemInfo(&si);
00638 func(GetCurrentProcess(), si.dwActiveProcessorMask);
00639 }
00640 #endif
00641 #endif
00642
00643 #ifdef __EMX__
00644
00645 _wildcard(&argc, &argv);
00646 #endif
00647
00648 for (i = 0; i < max_nogap; ++i) {
00649 nogap_inPath[i] = malloc(PATH_MAX + 1);
00650 }
00651
00652 memset(inPath, 0, sizeof(inPath));
00653
00654 frontend_open_console();
00655
00656
00657 input_format = sf_unknown;
00658 if (NULL == (gf = lame_init())) {
00659 error_printf("fatal error during initialization\n");
00660 frontend_close_console();
00661 return 1;
00662 }
00663 lame_set_errorf(gf, &frontend_errorf);
00664 lame_set_debugf(gf, &frontend_debugf);
00665 lame_set_msgf(gf, &frontend_msgf);
00666 if (argc <= 1) {
00667 usage(stderr, argv[0]);
00668 lame_close(gf);
00669 frontend_close_console();
00670 return 1;
00671 }
00672
00673
00674
00675
00676
00677
00678
00679 parse_args_from_string(gf, getenv("LAMEOPT"), inPath, outPath);
00680 ret = parse_args(gf, argc, argv, inPath, outPath, nogap_inPath, &max_nogap);
00681 if (ret < 0) {
00682 lame_close(gf);
00683 frontend_close_console();
00684 return ret == -2 ? 0 : 1;
00685 }
00686 if (update_interval < 0.)
00687 update_interval = 2.;
00688
00689 if (outPath[0] != '\0' && max_nogap > 0) {
00690 strncpy(nogapdir, outPath, PATH_MAX + 1);
00691 nogapout = 1;
00692 }
00693
00694
00695
00696 if (max_nogap > 0) {
00697
00698
00699 parse_nogap_filenames(nogapout, nogap_inPath[0], outPath, nogapdir);
00700 outf = init_files(gf, nogap_inPath[0], outPath, &enc_delay, &enc_padding);
00701 }
00702 else {
00703 outf = init_files(gf, inPath, outPath, &enc_delay, &enc_padding);
00704 }
00705 if (outf == NULL) {
00706 lame_close(gf);
00707 frontend_close_console();
00708 return -1;
00709 }
00710
00711
00712
00713
00714 i = lame_init_params(gf);
00715 if (i < 0) {
00716 if (i == -1) {
00717 display_bitrates(stderr);
00718 }
00719 error_printf("fatal error during initialization\n");
00720 lame_close(gf);
00721 frontend_close_console();
00722 return i;
00723 }
00724
00725 if (silent > 0
00726 #ifndef RH_HIST
00727 || lame_get_VBR(gf) == vbr_off
00728 #endif
00729 ) {
00730 brhist = 0;
00731 }
00732
00733
00734 if (lame_get_decode_only(gf)) {
00735
00736 if (mp3_delay_set)
00737 lame_decoder(gf, outf, mp3_delay, inPath, outPath, &enc_delay, &enc_padding);
00738 else
00739 lame_decoder(gf, outf, 0, inPath, outPath, &enc_delay, &enc_padding);
00740
00741 }
00742 else {
00743 if (max_nogap > 0) {
00744
00745
00746
00747 for (i = 0; i < max_nogap; ++i) {
00748 int use_flush_nogap = (i != (max_nogap - 1));
00749 if (i > 0) {
00750 parse_nogap_filenames(nogapout, nogap_inPath[i], outPath, nogapdir);
00751
00752
00753 outf = init_files(gf, nogap_inPath[i], outPath, &enc_delay, &enc_padding);
00754 }
00755 brhist_init_package(gf);
00756 lame_set_nogap_total(gf, max_nogap);
00757 lame_set_nogap_currentindex(gf, i);
00758 ret = lame_encoder(gf, outf, use_flush_nogap, nogap_inPath[i], outPath);
00759
00760 if (silent <= 0)
00761 print_lame_tag_leading_info(gf);
00762 lame_mp3_tags_fid(gf, outf);
00763
00764 if (silent <= 0)
00765 print_trailing_info(gf);
00766
00767 fclose(outf);
00768 close_infile();
00769
00770
00771
00772 if (use_flush_nogap)
00773 lame_init_bitstream(gf);
00774 }
00775 lame_close(gf);
00776
00777 }
00778 else {
00779
00780
00781
00782 brhist_init_package(gf);
00783 ret = lame_encoder(gf, outf, 0, inPath, outPath);
00784
00785 if (silent <= 0)
00786 print_lame_tag_leading_info(gf);
00787 lame_mp3_tags_fid(gf, outf);
00788
00789 if (silent <= 0)
00790 print_trailing_info(gf);
00791
00792 fclose(outf);
00793 close_infile();
00794 lame_close(gf);
00795 }
00796 }
00797 frontend_close_console();
00798 return ret;
00799 }