2 * Command line frontend program
4 * Copyright (c) 1999 Mark Taylor
5 * 2000 Takehiro TOMINAGA
6 * 2010-2011 Robert Hegemann
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 /* $Id: lame_main.c,v 1.9.2.1 2011/11/18 08:38:04 robert Exp $ */
39 # define strrchr rindex
41 char *strchr(), *strrchr();
43 # define memcpy(d, s, n) bcopy ((s), (d), (n))
44 # define memmove(d, s, n) bcopy ((s), (d), (n))
53 /* woraround for SunOS 4.x, it has SEEK_* defined here */
63 main.c is example code for how to use libmp3lame.a. To use this library,
64 you only need the library and lame.h. All other .h files are private
72 #include "get_audio.h"
73 #include "timestatus.h"
87 /************************************************************************
91 * PURPOSE: MPEG-1,2 Layer III encoder with GPSYCHO
92 * psychoacoustic model.
94 ************************************************************************/
98 parse_args_from_string(lame_global_flags * const gfp, const char *p, char *inPath, char *outPath)
99 { /* Quick & very Dirty */
106 if (p == NULL || *p == '\0')
109 f = q = malloc(strlen(p) + 1);
115 while (*q != ' ' && *q != '\0')
123 ret = parse_args(gfp, c, r, inPath, outPath, NULL, NULL);
133 init_files(lame_global_flags * gf, char const *inPath, char const *outPath)
136 /* Mostly it is not useful to use the same input and output name.
137 This test is very easy and buggy and don't recognize different names
138 assigning the same file
140 if (0 != strcmp("-", outPath) && 0 == strcmp(inPath, outPath)) {
141 error_printf("Input file and Output file are the same. Abort.\n");
145 /* open the wav/aiff/raw pcm or mp3 input file. This call will
146 * open the file, try to parse the headers and
147 * set gf.samplerate, gf.num_channels, gf.num_samples.
148 * if you want to do your own file input, skip this call and set
149 * samplerate, num_channels and num_samples yourself.
151 if (init_infile(gf, inPath) < 0) {
152 error_printf("Can't init infile '%s'\n", inPath);
155 if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
156 error_printf("Can't init outfile '%s'\n", outPath);
165 printInputFormat(lame_t gfp)
167 int const v_main = 2 - lame_get_version(gfp);
168 char const *v_ex = lame_get_out_samplerate(gfp) < 16000 ? ".5" : "";
169 switch (global_reader.input_format) {
170 case sf_mp123: /* FIXME: !!! */
173 console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "III");
176 console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "II");
179 console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "I");
182 console_printf("raw PCM data");
185 console_printf("Microsoft WAVE");
188 console_printf("SGI/Apple AIFF");
191 console_printf("unknown");
196 /* the simple lame decoder */
197 /* After calling lame_init(), lame_init_params() and
198 * init_infile(), call this routine to read the input MP3 file
199 * and output .wav data to the specified file pointer*/
200 /* lame_decoder will ignore the first 528 samples, since these samples
201 * represent the mpglib delay (and are all 0). skip = number of additional
202 * samples to skip, to (for example) compensate for the encoder delay */
205 lame_decoder(lame_t gfp, FILE * outf, char *inPath, char *outPath)
207 short int Buffer[2][1152];
210 int tmp_num_channels = lame_get_num_channels(gfp);
211 int skip_start = samples_to_skip_at_start();
212 int skip_end = samples_to_skip_at_end();
213 DecoderProgress dp = 0;
215 if (!(tmp_num_channels >= 1 && tmp_num_channels <= 2)) {
216 error_printf("Internal error. Aborting.");
220 if (global_ui_config.silent < 9) {
221 console_printf("\rinput: %s%s(%g kHz, %i channel%s, ",
222 strcmp(inPath, "-") ? inPath : "<stdin>",
223 strlen(inPath) > 26 ? "\n\t" : " ",
224 lame_get_in_samplerate(gfp) / 1.e3,
225 tmp_num_channels, tmp_num_channels != 1 ? "s" : "");
227 printInputFormat(gfp);
229 console_printf(")\noutput: %s%s(16 bit, Microsoft WAVE)\n",
230 strcmp(outPath, "-") ? outPath : "<stdout>",
231 strlen(outPath) > 45 ? "\n\t" : " ");
234 console_printf("skipping initial %i samples (encoder+decoder delay)\n", skip_start);
236 console_printf("skipping final %i samples (encoder padding-decoder delay)\n", skip_end);
238 switch (global_reader.input_format) {
242 dp = decoder_progress_init(lame_get_num_samples(gfp),
243 global_decoder.mp3input_data.framesize);
249 dp = decoder_progress_init(lame_get_num_samples(gfp),
250 lame_get_in_samplerate(gfp) < 32000 ? 576 : 1152);
255 if (0 == global_decoder.disable_wav_header)
256 WriteWaveHeader(outf, 0x7FFFFFFF, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
257 /* unknown size, so write maximum 32 bit signed value */
261 iread = get_audio16(gfp, Buffer); /* read in 'iread' samples */
265 decoder_progress(dp, &global_decoder.mp3input_data, iread);
267 put_audio16(outf, Buffer, iread, tmp_num_channels);
271 i = (16 / 8) * tmp_num_channels;
274 if (global_ui_config.silent < 10)
275 error_printf("WAVE file contains 0 PCM samples\n");
278 else if (wavsize > 0xFFFFFFD0 / i) {
279 if (global_ui_config.silent < 10)
280 error_printf("Very huge WAVE file, can't set filesize accordingly\n");
281 wavsize = 0xFFFFFFD0;
286 /* if outf is seekable, rewind and adjust length */
287 if (!global_decoder.disable_wav_header && strcmp("-", outPath)
288 && !fseek(outf, 0l, SEEK_SET))
289 WriteWaveHeader(outf, (int) wavsize, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
294 decoder_progress_finish(dp);
301 print_trailing_info(lame_global_flags * gf)
303 if (lame_get_findReplayGain(gf)) {
304 int RadioGain = lame_get_RadioGain(gf);
305 console_printf("ReplayGain: %s%.1fdB\n", RadioGain > 0 ? "+" : "",
306 ((float) RadioGain) / 10.0);
307 if (RadioGain > 0x1FE || RadioGain < -0x1FE)
309 ("WARNING: ReplayGain exceeds the -51dB to +51dB range. Such a result is too\n"
310 " high to be stored in the header.\n");
313 /* if (the user requested printing info about clipping) and (decoding
314 on the fly has actually been performed) */
315 if (global_ui_config.print_clipping_info && lame_get_decode_on_the_fly(gf)) {
316 float noclipGainChange = (float) lame_get_noclipGainChange(gf) / 10.0f;
317 float noclipScale = lame_get_noclipScale(gf);
319 if (noclipGainChange > 0.0) { /* clipping occurs */
321 ("WARNING: clipping occurs at the current gain. Set your decoder to decrease\n"
322 " the gain by at least %.1fdB or encode again ", noclipGainChange);
324 /* advice the user on the scale factor */
325 if (noclipScale > 0) {
326 console_printf("using --scale %.2f\n", noclipScale);
327 console_printf(" or less (the value under --scale is approximate).\n");
330 /* the user specified his own scale factor. We could suggest
331 * the scale factor of (32767.0/gfp->PeakSample)*(gfp->scale)
332 * but it's usually very inaccurate. So we'd rather advice him to
333 * disable scaling first and see our suggestion on the scale factor then. */
334 console_printf("using --scale <arg>\n"
335 " (For a suggestion on the optimal value of <arg> encode\n"
336 " with --scale 1 first)\n");
340 else { /* no clipping */
341 if (noclipGainChange > -0.1)
343 ("\nThe waveform does not clip and is less than 0.1dB away from full scale.\n");
346 ("\nThe waveform does not clip and is at least %.1fdB away from full scale.\n",
355 write_xing_frame(lame_global_flags * gf, FILE * outf, size_t offset)
357 unsigned char mp3buffer[LAME_MAXMP3BUFFER];
360 imp3 = lame_get_lametag_frame(gf, mp3buffer, sizeof(mp3buffer));
362 return 0; /* nothing to do */
364 if (global_ui_config.silent <= 0) {
365 console_printf("Writing LAME Tag...");
367 if (imp3 > sizeof(mp3buffer)) {
369 ("Error writing LAME-tag frame: buffer too small: buffer size=%d frame size=%d\n",
370 sizeof(mp3buffer), imp3);
373 if (fseek(outf, offset, SEEK_SET) != 0) {
374 error_printf("fatal error: can't update LAME-tag frame!\n");
377 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
378 if (owrite != imp3) {
379 error_printf("Error writing LAME-tag \n");
382 if (global_ui_config.silent <= 0) {
383 console_printf("done\n");
390 write_id3v1_tag(lame_t gf, FILE * outf)
392 unsigned char mp3buffer[128];
395 imp3 = lame_get_id3v1_tag(gf, mp3buffer, sizeof(mp3buffer));
399 if ((size_t) imp3 > sizeof(mp3buffer)) {
400 error_printf("Error writing ID3v1 tag: buffer too small: buffer size=%d ID3v1 size=%d\n",
401 sizeof(mp3buffer), imp3);
402 return 0; /* not critical */
404 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
405 if (owrite != imp3) {
406 error_printf("Error writing ID3v1 tag \n");
414 lame_encoder_loop(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
416 unsigned char mp3buffer[LAME_MAXMP3BUFFER];
418 int iread, imp3, owrite;
421 encoder_progress_begin(gf, inPath, outPath);
423 id3v2_size = lame_get_id3v2_tag(gf, 0, 0);
424 if (id3v2_size > 0) {
425 unsigned char *id3v2tag = malloc(id3v2_size);
427 imp3 = lame_get_id3v2_tag(gf, id3v2tag, id3v2_size);
428 owrite = (int) fwrite(id3v2tag, 1, imp3, outf);
430 if (owrite != imp3) {
431 encoder_progress_end(gf);
432 error_printf("Error writing ID3v2 tag \n");
438 unsigned char* id3v2tag = getOldTag(gf);
439 id3v2_size = sizeOfOldTag(gf);
440 if ( id3v2_size > 0 ) {
441 size_t owrite = fwrite(id3v2tag, 1, id3v2_size, outf);
442 if (owrite != id3v2_size) {
443 encoder_progress_end(gf);
444 error_printf("Error writing ID3v2 tag \n");
449 if (global_writer.flush_write == 1) {
453 /* encode until we hit eof */
455 /* read in 'iread' samples */
456 iread = get_audio(gf, Buffer);
459 encoder_progress(gf);
463 imp3 = lame_encode_buffer_int(gf, Buffer[0], Buffer[1], iread,
464 mp3buffer, sizeof(mp3buffer));
466 /* was our output buffer big enough? */
469 error_printf("mp3 buffer is not big enough... \n");
471 error_printf("mp3 internal error: error code=%i\n", imp3);
474 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
475 if (owrite != imp3) {
476 error_printf("Error writing mp3 output \n");
480 if (global_writer.flush_write == 1) {
486 imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
488 imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
492 error_printf("mp3 buffer is not big enough... \n");
494 error_printf("mp3 internal error: error code=%i\n", imp3);
499 encoder_progress_end(gf);
501 owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
502 if (owrite != imp3) {
503 error_printf("Error writing mp3 output \n");
506 if (global_writer.flush_write == 1) {
509 imp3 = write_id3v1_tag(gf, outf);
510 if (global_writer.flush_write == 1) {
516 write_xing_frame(gf, outf, id3v2_size);
517 if (global_writer.flush_write == 1) {
520 if (global_ui_config.silent <= 0) {
521 print_trailing_info(gf);
528 lame_encoder(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
532 ret = lame_encoder_loop(gf, outf, nogap, inPath, outPath);
533 fclose(outf); /* close the output file */
534 close_infile(); /* close the input file */
540 parse_nogap_filenames(int nogapout, char const *inPath, char *outPath, char *outdir)
545 /* FIXME: replace strcpy by safer strncpy */
546 strcpy(outPath, outdir);
548 strncpy(outPath, inPath, PATH_MAX + 1 - 4);
550 /* nuke old extension, if one */
551 if (outPath[n - 3] == 'w'
552 && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
553 outPath[n - 3] = 'm';
554 outPath[n - 2] = 'p';
555 outPath[n - 1] = '3';
558 outPath[n + 0] = '.';
559 outPath[n + 1] = 'm';
560 outPath[n + 2] = 'p';
561 outPath[n + 3] = '3';
567 slasher += PATH_MAX + 1 - 4;
569 /* backseek to last dir delemiter */
570 while (*slasher != '/' && *slasher != '\\' && slasher != inPath && *slasher != ':') {
574 /* skip one foward if needed */
575 if (slasher != inPath
576 && (outPath[strlen(outPath) - 1] == '/'
577 || outPath[strlen(outPath) - 1] == '\\' || outPath[strlen(outPath) - 1] == ':'))
579 else if (slasher == inPath
580 && (outPath[strlen(outPath) - 1] != '/'
582 outPath[strlen(outPath) - 1] != '\\' && outPath[strlen(outPath) - 1] != ':'))
583 /* FIXME: replace strcat by safer strncat */
585 strncat(outPath, "\\", PATH_MAX + 1 - 4);
587 strncat(outPath, "\\", PATH_MAX + 1 - 4);
589 strncat(outPath, "/", PATH_MAX + 1 - 4);
592 strncat(outPath, slasher, PATH_MAX + 1 - 4);
594 /* nuke old extension */
595 if (outPath[n - 3] == 'w'
596 && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
597 outPath[n - 3] = 'm';
598 outPath[n - 2] = 'p';
599 outPath[n - 1] = '3';
602 outPath[n + 0] = '.';
603 outPath[n + 1] = 'm';
604 outPath[n + 2] = 'p';
605 outPath[n + 3] = '3';
613 lame_main(lame_t gf, int argc, char **argv)
615 char inPath[PATH_MAX + 1];
616 char outPath[PATH_MAX + 1];
617 char nogapdir[PATH_MAX + 1];
618 /* support for "nogap" encoding of up to 200 .wav files */
619 #define MAX_NOGAP 200
621 int max_nogap = MAX_NOGAP;
622 char nogap_inPath_[MAX_NOGAP][PATH_MAX + 1];
623 char *nogap_inPath[MAX_NOGAP];
629 lame_set_msgf(gf, &frontend_msgf);
630 lame_set_errorf(gf, &frontend_errorf);
631 lame_set_debugf(gf, &frontend_debugf);
633 usage(stderr, argv[0]); /* no command-line args, print usage, exit */
637 memset(inPath, 0, sizeof(inPath));
638 memset(nogap_inPath_, 0, sizeof(nogap_inPath_));
639 for (i = 0; i < MAX_NOGAP; ++i) {
640 nogap_inPath[i] = &nogap_inPath_[i][0];
643 /* parse the command line arguments, setting various flags in the
644 * struct 'gf'. If you want to parse your own arguments,
645 * or call libmp3lame from a program which uses a GUI to set arguments,
646 * skip this call and set the values of interest in the gf struct.
647 * (see the file API and lame.h for documentation about these parameters)
650 char *str = lame_getenv("LAMEOPT");
651 parse_args_from_string(gf, str, inPath, outPath);
654 ret = parse_args(gf, argc, argv, inPath, outPath, nogap_inPath, &max_nogap);
656 return ret == -2 ? 0 : 1;
658 if (global_ui_config.update_interval < 0.)
659 global_ui_config.update_interval = 2.;
661 if (outPath[0] != '\0' && max_nogap > 0) {
662 strncpy(nogapdir, outPath, PATH_MAX + 1);
666 /* initialize input file. This also sets samplerate and as much
667 other data on the input file as available in the headers */
669 /* for nogap encoding of multiple input files, it is not possible to
670 * specify the output file name, only an optional output directory. */
671 parse_nogap_filenames(nogapout, nogap_inPath[0], outPath, nogapdir);
672 outf = init_files(gf, nogap_inPath[0], outPath);
675 outf = init_files(gf, inPath, outPath);
680 /* turn off automatic writing of ID3 tag data into mp3 stream
681 * we have to call it before 'lame_init_params', because that
682 * function would spit out ID3v2 tag data.
684 lame_set_write_id3tag_automatic(gf, 0);
686 /* Now that all the options are set, lame needs to analyze them and
687 * set some more internal options and check for problems
689 ret = lame_init_params(gf);
692 display_bitrates(stderr);
694 error_printf("fatal error during initialization\n");
698 if (global_ui_config.silent > 0) {
699 global_ui_config.brhist = 0; /* turn off VBR histogram */
702 if (lame_get_decode_only(gf)) {
703 /* decode an mp3 file to a .wav */
704 ret = lame_decoder(gf, outf, inPath, outPath);
706 else if (max_nogap == 0) {
707 /* encode a single input file */
708 ret = lame_encoder(gf, outf, 0, inPath, outPath);
711 /* encode multiple input files using nogap option */
712 for (i = 0; i < max_nogap; ++i) {
713 int use_flush_nogap = (i != (max_nogap - 1));
715 parse_nogap_filenames(nogapout, nogap_inPath[i], outPath, nogapdir);
716 /* note: if init_files changes anything, like
717 samplerate, num_channels, etc, we are screwed */
718 outf = init_files(gf, nogap_inPath[i], outPath);
719 /* reinitialize bitstream for next encoding. this is normally done
720 * by lame_init_params(), but we cannot call that routine twice */
721 lame_init_bitstream(gf);
723 lame_set_nogap_total(gf, max_nogap);
724 lame_set_nogap_currentindex(gf, i);
725 ret = lame_encoder(gf, outf, use_flush_nogap, nogap_inPath[i], outPath);