/* mp3enc - encode audio files in MP3 format */

/*
 *	Command line frontend program
 *
 *	Copyright (c) 1999 Mark Taylor
 *                    2000 Takehiro TOMIANGA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/* $Id: main.c,v 1.46 2001/03/11 11:24:25 aleidinger Exp $ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <memory.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

/*
 main.c is example code for how to use libmp3lame.a.  To use this library,
 you only need the library and lame.h.  All other .h files are private
 to the library.
*/
#include "lame.h"

#include "brhist.h"
#include "parse.h"
#include "main.h"
#include "get_audio.h"
#include "timestatus.h"

/*
*
* main
*
* PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
* psychoacoustic model.
*
*/

int
parse_args_from_string(lame_global_flags *const gfp, const char *p)
{
	/* Quick & very Dirty */
	int c = 0, ret;
	char *f, *q, *r[128];

	if (p == NULL || *p == '\0')
		return 0;

	f = q = malloc(strlen(p) + 1);
	strcpy (q, p);

	r[c++] = "lhama";
	for (;;) {
		r[c++] = q;
		while (*q != ' ' && *q != '\0')
			q++;
		if (*q == '\0')
			break;
		*q++ = '\0';
	}
	r[c] = NULL;

	ret = parse_args(gfp, c, r);
	free(f);
	return ret;
}

int
main(int argc, char **argv)
{
	int i, iread, imp3, ret;
	short Buffer[2][1152];
	unsigned char mp3buffer[LAME_MAXMP3BUFFER];
	FILE *outf;
	lame_global_flags *gf;
	static char inPath[]  = "-";
	static char outPath[] = "-";
	static const char *mode_names[2][4] = {
		{ "stereo", "j-stereo", "dual-ch", "single-ch" },
		{ "stereo", "force-ms", "dual-ch", "single-ch" }
	};

	/* initialize libmp3lame */
	input_format = sf_unknown;
	if (NULL == (gf = lame_init()) ) {
		fprintf(stderr, "mp3enc: fatal error during initialization\n");
		return 1;
	}
	/*
	 * parse the command line arguments, setting various flags in the
	 * struct 'gf'.  If you want to parse your own arguments,
	 * or call libmp3lame from a program which uses a GUI to set arguments,
	 * skip this call and set the values of interest in the gf struct.
	 * (see the file API & lame.h for documentation about these parameters)
	 */
	parse_args_from_string(gf, getenv("LAMEOPT"));
	ret = parse_args(gf, argc, argv);
	if (ret < 0)
		return ret == -2? 0: 1;
	if (update_interval < 0.)
		update_interval = 2.;

	/*
	 * open the wav/aiff/raw pcm or mp3 input file.  This call will
	 * open the file, try to parse the headers and
	 * set gf.samplerate, gf.num_channels, gf.num_samples.
	 * if you want to do your own file input, skip this call and set
	 * samplerate, num_channels and num_samples yourself.
	 */
	init_infile(gf, inPath);
	if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
		fprintf(stderr, "Can't init outfile '%s'\n", outPath);
		return -42;
	}

	/*
	 * Now that all the options are set, lame needs to analyze them and
	 * set some more internal options and check for problems
	 */
	i = lame_init_params(gf);
	if (i < 0) {
		if (i == -1)
			display_bitrates(stderr);
		fprintf(stderr, "fatal error during initialization\n");
		return 1;
	}

	if (silent || gf->VBR == vbr_off)
		brhist = 0;			/* turn off VBR histogram */

#ifdef BRHIST
	if (brhist) {
		if (brhist_init(gf, gf->VBR_min_bitrate_kbps,
		    gf->VBR_max_bitrate_kbps))
			/* fail to initialize */
			brhist = 0;
	} else
		brhist_init(gf, 128, 128);	/* Dirty hack */
#endif


#ifdef HAVE_VORBIS
	if (lame_get_ogg( gf ) ) {
		lame_encode_ogg_init(gf);
		gf->VBR = vbr_off;	/* ignore lame's various VBR modes */
	}
#endif
	if (0 == lame_get_decode_only( gf ) && silent < 10 ) {
		if (0)
			fprintf(stderr, "Encoding as %g kHz ",
				1.e-3 * lame_get_out_samplerate( gf ) );

		if (lame_get_ogg(gf)) {
			if (0)
				fprintf(stderr, "VBR Ogg Vorbis\n" );
		} else {
			const char *appendix = "";

			switch (gf->VBR ) {
			case vbr_mt:
			case vbr_rh:
			case vbr_mtrh:
				appendix = "ca. ";
				if (0)
					fprintf(stderr, "VBR(q=%i)", gf->VBR_q );
				break;
			case vbr_abr:
				if (0)
					fprintf(stderr, "average %d kbps",
						gf->VBR_mean_bitrate_kbps);
				break;
			default:
				if (0)
					fprintf(stderr, "%3d Kb/s", gf->brate);
				break;
			}
			if (0)
				fprintf(stderr, " %s MPEG-%u%s Layer III (%s%gx) qval=%i\n",
					mode_names[gf->force_ms][gf->mode],
					2 - gf->version,
					lame_get_out_samplerate(gf) < 16000?
					".5": "", appendix,
					0.1 * (int)(10.*gf->compression_ratio + 0.5),
					lame_get_quality(gf));
		}
		fflush(stderr);
	}

	if (lame_get_decode_only(gf))
		/* decode an mp3 file to a .wav */
		if (mp3_delay_set)
			lame_decoder(gf, outf, mp3_delay, inPath, outPath);
		else
			lame_decoder(gf, outf, gf->encoder_delay, inPath, outPath);
	else {
		/* encode until we hit eof */
		do {
			/* read in 'iread' samples */
			iread = get_audio(gf, Buffer);

			/* status display  */
			if (!silent)
				if (update_interval > 0)
					timestatus_klemm(gf);
				else {
					if (0 == gf->frameNum % 50) {
#ifdef BRHIST
						brhist_jump_back();
#endif
						timestatus(lame_get_out_samplerate(gf),
							gf->frameNum,
							gf->totalframes,
							gf->framesize );
#ifdef BRHIST
						if (brhist)
							brhist_disp(gf);
#endif
					}
				}

			/* encode */
			imp3 = lame_encode_buffer(gf, Buffer[0], Buffer[1], iread,
				mp3buffer, sizeof(mp3buffer));

			/* was our output buffer big enough? */
			if (imp3 < 0) {
				if (imp3 == -1)
					fprintf(stderr, "mp3 buffer is not big enough... \n");
				else
					fprintf(stderr, "mp3 internal error:  error code=%i\n", imp3);
				return 1;
			}

			if (fwrite(mp3buffer, 1, imp3, outf) != imp3) {
				fprintf(stderr, "Error writing mp3 output \n");
				return 1;
			}
		} while (iread);
		/* may return one more mp3 frame */
		imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer));
		if (imp3 < 0) {
			if (imp3 == -1)
				fprintf(stderr, "mp3 buffer is not big enough... \n");
			else
				fprintf(stderr, "mp3 internal error:  error code=%i\n", imp3);
			return 1;

		}
		if (!silent) {
#ifdef BRHIST
			brhist_jump_back();
#endif
			timestatus(lame_get_out_samplerate(gf),
				gf->frameNum,
				gf->totalframes,
				gf->framesize);
#ifdef BRHIST
			if (brhist)
				brhist_disp(gf);
			brhist_disp_total(gf);
#endif
			timestatus_finish();
		}

		fwrite(mp3buffer, 1, imp3, outf);
		lame_mp3_tags_fid(gf, outf);	/* add VBR tags to mp3 file */
		lame_close(gf);
		fclose(outf);
	}
	close_infile();
	return 0;
}
