summaryrefslogtreecommitdiff
path: root/sys/src/cmd/audio/mp3enc/main.c
blob: e8f62e3cc70f74744541e55975a518b2399dad61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* 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;
}