1159b3361Sopenharmony_ci/*
2159b3361Sopenharmony_ci *      Command line frontend program
3159b3361Sopenharmony_ci *
4159b3361Sopenharmony_ci *      Copyright (c) 1999 Mark Taylor
5159b3361Sopenharmony_ci *                    2000 Takehiro TOMINAGA
6159b3361Sopenharmony_ci *                    2010-2017 Robert Hegemann
7159b3361Sopenharmony_ci *
8159b3361Sopenharmony_ci * This library is free software; you can redistribute it and/or
9159b3361Sopenharmony_ci * modify it under the terms of the GNU Library General Public
10159b3361Sopenharmony_ci * License as published by the Free Software Foundation; either
11159b3361Sopenharmony_ci * version 2 of the License, or (at your option) any later version.
12159b3361Sopenharmony_ci *
13159b3361Sopenharmony_ci * This library is distributed in the hope that it will be useful,
14159b3361Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15159b3361Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16159b3361Sopenharmony_ci * Library General Public License for more details.
17159b3361Sopenharmony_ci *
18159b3361Sopenharmony_ci * You should have received a copy of the GNU Library General Public
19159b3361Sopenharmony_ci * License along with this library; if not, write to the
20159b3361Sopenharmony_ci * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21159b3361Sopenharmony_ci * Boston, MA 02111-1307, USA.
22159b3361Sopenharmony_ci */
23159b3361Sopenharmony_ci
24159b3361Sopenharmony_ci/* $Id$ */
25159b3361Sopenharmony_ci
26159b3361Sopenharmony_ci#ifdef HAVE_CONFIG_H
27159b3361Sopenharmony_ci# include <config.h>
28159b3361Sopenharmony_ci#endif
29159b3361Sopenharmony_ci
30159b3361Sopenharmony_ci#include <assert.h>
31159b3361Sopenharmony_ci#include <stdio.h>
32159b3361Sopenharmony_ci
33159b3361Sopenharmony_ci#ifdef STDC_HEADERS
34159b3361Sopenharmony_ci# include <stdlib.h>
35159b3361Sopenharmony_ci# include <string.h>
36159b3361Sopenharmony_ci#else
37159b3361Sopenharmony_ci# ifndef HAVE_STRCHR
38159b3361Sopenharmony_ci#  define strchr index
39159b3361Sopenharmony_ci#  define strrchr rindex
40159b3361Sopenharmony_ci# endif
41159b3361Sopenharmony_cichar   *strchr(), *strrchr();
42159b3361Sopenharmony_ci# ifndef HAVE_MEMCPY
43159b3361Sopenharmony_ci#  define memcpy(d, s, n) bcopy ((s), (d), (n))
44159b3361Sopenharmony_ci#  define memmove(d, s, n) bcopy ((s), (d), (n))
45159b3361Sopenharmony_ci# endif
46159b3361Sopenharmony_ci#endif
47159b3361Sopenharmony_ci
48159b3361Sopenharmony_ci#ifdef HAVE_FCNTL_H
49159b3361Sopenharmony_ci# include <fcntl.h>
50159b3361Sopenharmony_ci#endif
51159b3361Sopenharmony_ci
52159b3361Sopenharmony_ci#ifdef __sun__
53159b3361Sopenharmony_ci/* woraround for SunOS 4.x, it has SEEK_* defined here */
54159b3361Sopenharmony_ci#include <unistd.h>
55159b3361Sopenharmony_ci#endif
56159b3361Sopenharmony_ci
57159b3361Sopenharmony_ci#if defined(_WIN32)
58159b3361Sopenharmony_ci# include <windows.h>
59159b3361Sopenharmony_ci#endif
60159b3361Sopenharmony_ci
61159b3361Sopenharmony_ci
62159b3361Sopenharmony_ci/*
63159b3361Sopenharmony_ci main.c is example code for how to use libmp3lame.a.  To use this library,
64159b3361Sopenharmony_ci you only need the library and lame.h.  All other .h files are private
65159b3361Sopenharmony_ci to the library.
66159b3361Sopenharmony_ci*/
67159b3361Sopenharmony_ci#include "lame.h"
68159b3361Sopenharmony_ci
69159b3361Sopenharmony_ci#include "console.h"
70159b3361Sopenharmony_ci#include "parse.h"
71159b3361Sopenharmony_ci#include "main.h"
72159b3361Sopenharmony_ci#include "get_audio.h"
73159b3361Sopenharmony_ci#include "timestatus.h"
74159b3361Sopenharmony_ci
75159b3361Sopenharmony_ci/* PLL 14/04/2000 */
76159b3361Sopenharmony_ci#if macintosh
77159b3361Sopenharmony_ci#include <console.h>
78159b3361Sopenharmony_ci#endif
79159b3361Sopenharmony_ci
80159b3361Sopenharmony_ci#ifdef WITH_DMALLOC
81159b3361Sopenharmony_ci#include <dmalloc.h>
82159b3361Sopenharmony_ci#endif
83159b3361Sopenharmony_ci
84159b3361Sopenharmony_ci
85159b3361Sopenharmony_ci
86159b3361Sopenharmony_ci
87159b3361Sopenharmony_ci/************************************************************************
88159b3361Sopenharmony_ci*
89159b3361Sopenharmony_ci* main
90159b3361Sopenharmony_ci*
91159b3361Sopenharmony_ci* PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
92159b3361Sopenharmony_ci* psychoacoustic model.
93159b3361Sopenharmony_ci*
94159b3361Sopenharmony_ci************************************************************************/
95159b3361Sopenharmony_ci
96159b3361Sopenharmony_ci
97159b3361Sopenharmony_cistatic FILE *
98159b3361Sopenharmony_ciinit_files(lame_global_flags * gf, char const *inPath, char const *outPath)
99159b3361Sopenharmony_ci{
100159b3361Sopenharmony_ci    FILE   *outf;
101159b3361Sopenharmony_ci    /* Mostly it is not useful to use the same input and output name.
102159b3361Sopenharmony_ci       This test is very easy and buggy and don't recognize different names
103159b3361Sopenharmony_ci       assigning the same file
104159b3361Sopenharmony_ci     */
105159b3361Sopenharmony_ci    if (0 != strcmp("-", outPath) && 0 == strcmp(inPath, outPath)) {
106159b3361Sopenharmony_ci        error_printf("Input file and Output file are the same. Abort.\n");
107159b3361Sopenharmony_ci        return NULL;
108159b3361Sopenharmony_ci    }
109159b3361Sopenharmony_ci
110159b3361Sopenharmony_ci    /* open the wav/aiff/raw pcm or mp3 input file.  This call will
111159b3361Sopenharmony_ci     * open the file, try to parse the headers and
112159b3361Sopenharmony_ci     * set gf.samplerate, gf.num_channels, gf.num_samples.
113159b3361Sopenharmony_ci     * if you want to do your own file input, skip this call and set
114159b3361Sopenharmony_ci     * samplerate, num_channels and num_samples yourself.
115159b3361Sopenharmony_ci     */
116159b3361Sopenharmony_ci    if (init_infile(gf, inPath) < 0) {
117159b3361Sopenharmony_ci        error_printf("Can't init infile '%s'\n", inPath);
118159b3361Sopenharmony_ci        return NULL;
119159b3361Sopenharmony_ci    }
120159b3361Sopenharmony_ci    if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
121159b3361Sopenharmony_ci        error_printf("Can't init outfile '%s'\n", outPath);
122159b3361Sopenharmony_ci        return NULL;
123159b3361Sopenharmony_ci    }
124159b3361Sopenharmony_ci
125159b3361Sopenharmony_ci    return outf;
126159b3361Sopenharmony_ci}
127159b3361Sopenharmony_ci
128159b3361Sopenharmony_ci
129159b3361Sopenharmony_cistatic void
130159b3361Sopenharmony_ciprintInputFormat(lame_t gfp)
131159b3361Sopenharmony_ci{
132159b3361Sopenharmony_ci    int const v_main = 2 - lame_get_version(gfp);
133159b3361Sopenharmony_ci    char const *v_ex = lame_get_out_samplerate(gfp) < 16000 ? ".5" : "";
134159b3361Sopenharmony_ci    switch (global_reader.input_format) {
135159b3361Sopenharmony_ci    case sf_mp123:     /* FIXME: !!! */
136159b3361Sopenharmony_ci        break;
137159b3361Sopenharmony_ci    case sf_mp3:
138159b3361Sopenharmony_ci        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "III");
139159b3361Sopenharmony_ci        break;
140159b3361Sopenharmony_ci    case sf_mp2:
141159b3361Sopenharmony_ci        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "II");
142159b3361Sopenharmony_ci        break;
143159b3361Sopenharmony_ci    case sf_mp1:
144159b3361Sopenharmony_ci        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "I");
145159b3361Sopenharmony_ci        break;
146159b3361Sopenharmony_ci    case sf_raw:
147159b3361Sopenharmony_ci        console_printf("raw PCM data");
148159b3361Sopenharmony_ci        break;
149159b3361Sopenharmony_ci    case sf_wave:
150159b3361Sopenharmony_ci        console_printf("Microsoft WAVE");
151159b3361Sopenharmony_ci        break;
152159b3361Sopenharmony_ci    case sf_aiff:
153159b3361Sopenharmony_ci        console_printf("SGI/Apple AIFF");
154159b3361Sopenharmony_ci        break;
155159b3361Sopenharmony_ci    default:
156159b3361Sopenharmony_ci        console_printf("unknown");
157159b3361Sopenharmony_ci        break;
158159b3361Sopenharmony_ci    }
159159b3361Sopenharmony_ci}
160159b3361Sopenharmony_ci
161159b3361Sopenharmony_ci/* the simple lame decoder */
162159b3361Sopenharmony_ci/* After calling lame_init(), lame_init_params() and
163159b3361Sopenharmony_ci * init_infile(), call this routine to read the input MP3 file
164159b3361Sopenharmony_ci * and output .wav data to the specified file pointer*/
165159b3361Sopenharmony_ci/* lame_decoder will ignore the first 528 samples, since these samples
166159b3361Sopenharmony_ci * represent the mpglib delay (and are all 0).  skip = number of additional
167159b3361Sopenharmony_ci * samples to skip, to (for example) compensate for the encoder delay */
168159b3361Sopenharmony_ci
169159b3361Sopenharmony_cistatic int
170159b3361Sopenharmony_cilame_decoder_loop(lame_t gfp, FILE * outf, char *inPath, char *outPath)
171159b3361Sopenharmony_ci{
172159b3361Sopenharmony_ci    short int Buffer[2][1152];
173159b3361Sopenharmony_ci    int     i, iread;
174159b3361Sopenharmony_ci    double  wavsize;
175159b3361Sopenharmony_ci    int     tmp_num_channels = lame_get_num_channels(gfp);
176159b3361Sopenharmony_ci    int     skip_start = samples_to_skip_at_start();
177159b3361Sopenharmony_ci    int     skip_end = samples_to_skip_at_end();
178159b3361Sopenharmony_ci    DecoderProgress dp = 0;
179159b3361Sopenharmony_ci
180159b3361Sopenharmony_ci    if (!(tmp_num_channels >= 1 && tmp_num_channels <= 2)) {
181159b3361Sopenharmony_ci        error_printf("Internal error.  Aborting.");
182159b3361Sopenharmony_ci        return -1;
183159b3361Sopenharmony_ci    }
184159b3361Sopenharmony_ci
185159b3361Sopenharmony_ci    if (global_ui_config.silent < 9) {
186159b3361Sopenharmony_ci        console_printf("\rinput:  %s%s(%g kHz, %i channel%s, ",
187159b3361Sopenharmony_ci                       strcmp(inPath, "-") ? inPath : "<stdin>",
188159b3361Sopenharmony_ci                       strlen(inPath) > 26 ? "\n\t" : "  ",
189159b3361Sopenharmony_ci                       lame_get_in_samplerate(gfp) / 1.e3,
190159b3361Sopenharmony_ci                       tmp_num_channels, tmp_num_channels != 1 ? "s" : "");
191159b3361Sopenharmony_ci
192159b3361Sopenharmony_ci        printInputFormat(gfp);
193159b3361Sopenharmony_ci
194159b3361Sopenharmony_ci        console_printf(")\noutput: %s%s(16 bit, Microsoft WAVE)\n",
195159b3361Sopenharmony_ci                       strcmp(outPath, "-") ? outPath : "<stdout>",
196159b3361Sopenharmony_ci                       strlen(outPath) > 45 ? "\n\t" : "  ");
197159b3361Sopenharmony_ci
198159b3361Sopenharmony_ci        if (skip_start > 0)
199159b3361Sopenharmony_ci            console_printf("skipping initial %i samples (encoder+decoder delay)\n", skip_start);
200159b3361Sopenharmony_ci        if (skip_end > 0)
201159b3361Sopenharmony_ci            console_printf("skipping final %i samples (encoder padding-decoder delay)\n", skip_end);
202159b3361Sopenharmony_ci
203159b3361Sopenharmony_ci        switch (global_reader.input_format) {
204159b3361Sopenharmony_ci        case sf_mp3:
205159b3361Sopenharmony_ci        case sf_mp2:
206159b3361Sopenharmony_ci        case sf_mp1:
207159b3361Sopenharmony_ci            dp = decoder_progress_init(lame_get_num_samples(gfp),
208159b3361Sopenharmony_ci                                       global_decoder.mp3input_data.framesize);
209159b3361Sopenharmony_ci            break;
210159b3361Sopenharmony_ci        case sf_raw:
211159b3361Sopenharmony_ci        case sf_wave:
212159b3361Sopenharmony_ci        case sf_aiff:
213159b3361Sopenharmony_ci        default:
214159b3361Sopenharmony_ci            dp = decoder_progress_init(lame_get_num_samples(gfp),
215159b3361Sopenharmony_ci                                       lame_get_in_samplerate(gfp) < 32000 ? 576 : 1152);
216159b3361Sopenharmony_ci            break;
217159b3361Sopenharmony_ci        }
218159b3361Sopenharmony_ci    }
219159b3361Sopenharmony_ci
220159b3361Sopenharmony_ci    if (0 == global_decoder.disable_wav_header)
221159b3361Sopenharmony_ci        WriteWaveHeader(outf, 0x7FFFFFFF, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
222159b3361Sopenharmony_ci    /* unknown size, so write maximum 32 bit signed value */
223159b3361Sopenharmony_ci
224159b3361Sopenharmony_ci    wavsize = 0;
225159b3361Sopenharmony_ci    do {
226159b3361Sopenharmony_ci        iread = get_audio16(gfp, Buffer); /* read in 'iread' samples */
227159b3361Sopenharmony_ci        if (iread >= 0) {
228159b3361Sopenharmony_ci            wavsize += iread;
229159b3361Sopenharmony_ci            if (dp != 0) {
230159b3361Sopenharmony_ci                decoder_progress(dp, &global_decoder.mp3input_data, iread);
231159b3361Sopenharmony_ci            }
232159b3361Sopenharmony_ci            put_audio16(outf, Buffer, iread, tmp_num_channels);
233159b3361Sopenharmony_ci        }
234159b3361Sopenharmony_ci    } while (iread > 0);
235159b3361Sopenharmony_ci
236159b3361Sopenharmony_ci    i = (16 / 8) * tmp_num_channels;
237159b3361Sopenharmony_ci    assert(i > 0);
238159b3361Sopenharmony_ci    if (wavsize <= 0) {
239159b3361Sopenharmony_ci        if (global_ui_config.silent < 10)
240159b3361Sopenharmony_ci            error_printf("WAVE file contains 0 PCM samples\n");
241159b3361Sopenharmony_ci        wavsize = 0;
242159b3361Sopenharmony_ci    }
243159b3361Sopenharmony_ci    else if (wavsize > 0xFFFFFFD0 / i) {
244159b3361Sopenharmony_ci        if (global_ui_config.silent < 10)
245159b3361Sopenharmony_ci            error_printf("Very huge WAVE file, can't set filesize accordingly\n");
246159b3361Sopenharmony_ci        wavsize = 0xFFFFFFD0;
247159b3361Sopenharmony_ci    }
248159b3361Sopenharmony_ci    else {
249159b3361Sopenharmony_ci        wavsize *= i;
250159b3361Sopenharmony_ci    }
251159b3361Sopenharmony_ci    /* if outf is seekable, rewind and adjust length */
252159b3361Sopenharmony_ci    if (!global_decoder.disable_wav_header && strcmp("-", outPath)
253159b3361Sopenharmony_ci        && !fseek(outf, 0l, SEEK_SET))
254159b3361Sopenharmony_ci        WriteWaveHeader(outf, (int) wavsize, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
255159b3361Sopenharmony_ci
256159b3361Sopenharmony_ci    if (dp != 0)
257159b3361Sopenharmony_ci        decoder_progress_finish(dp);
258159b3361Sopenharmony_ci    return 0;
259159b3361Sopenharmony_ci}
260159b3361Sopenharmony_ci
261159b3361Sopenharmony_cistatic int
262159b3361Sopenharmony_cilame_decoder(lame_t gfp, FILE * outf, char *inPath, char *outPath)
263159b3361Sopenharmony_ci{
264159b3361Sopenharmony_ci    int     ret;
265159b3361Sopenharmony_ci
266159b3361Sopenharmony_ci    ret = lame_decoder_loop(gfp, outf, inPath, outPath);
267159b3361Sopenharmony_ci    fclose(outf);       /* close the output file */
268159b3361Sopenharmony_ci    close_infile();     /* close the input file */
269159b3361Sopenharmony_ci    return ret;
270159b3361Sopenharmony_ci}
271159b3361Sopenharmony_ci
272159b3361Sopenharmony_ci
273159b3361Sopenharmony_cistatic void
274159b3361Sopenharmony_ciprint_trailing_info(lame_global_flags * gf)
275159b3361Sopenharmony_ci{
276159b3361Sopenharmony_ci    if (lame_get_findReplayGain(gf)) {
277159b3361Sopenharmony_ci        int     RadioGain = lame_get_RadioGain(gf);
278159b3361Sopenharmony_ci        console_printf("ReplayGain: %s%.1fdB\n", RadioGain > 0 ? "+" : "",
279159b3361Sopenharmony_ci                       ((float) RadioGain) / 10.0);
280159b3361Sopenharmony_ci        if (RadioGain > 0x1FE || RadioGain < -0x1FE)
281159b3361Sopenharmony_ci            error_printf
282159b3361Sopenharmony_ci                ("WARNING: ReplayGain exceeds the -51dB to +51dB range. Such a result is too\n"
283159b3361Sopenharmony_ci                 "         high to be stored in the header.\n");
284159b3361Sopenharmony_ci    }
285159b3361Sopenharmony_ci
286159b3361Sopenharmony_ci    /* if (the user requested printing info about clipping) and (decoding
287159b3361Sopenharmony_ci       on the fly has actually been performed) */
288159b3361Sopenharmony_ci    if (global_ui_config.print_clipping_info && lame_get_decode_on_the_fly(gf)) {
289159b3361Sopenharmony_ci        float   noclipGainChange = (float) lame_get_noclipGainChange(gf) / 10.0f;
290159b3361Sopenharmony_ci        float   noclipScale = lame_get_noclipScale(gf);
291159b3361Sopenharmony_ci
292159b3361Sopenharmony_ci        if (noclipGainChange > 0.0) { /* clipping occurs */
293159b3361Sopenharmony_ci            console_printf
294159b3361Sopenharmony_ci                ("WARNING: clipping occurs at the current gain. Set your decoder to decrease\n"
295159b3361Sopenharmony_ci                 "         the  gain  by  at least %.1fdB or encode again ", noclipGainChange);
296159b3361Sopenharmony_ci
297159b3361Sopenharmony_ci            /* advice the user on the scale factor */
298159b3361Sopenharmony_ci            if (noclipScale > 0) {
299159b3361Sopenharmony_ci                console_printf("using  --scale %.2f\n", noclipScale * lame_get_scale(gf));
300159b3361Sopenharmony_ci                console_printf("         or less (the value under --scale is approximate).\n");
301159b3361Sopenharmony_ci            }
302159b3361Sopenharmony_ci            else {
303159b3361Sopenharmony_ci                /* the user specified his own scale factor. We could suggest
304159b3361Sopenharmony_ci                 * the scale factor of (32767.0/gfp->PeakSample)*(gfp->scale)
305159b3361Sopenharmony_ci                 * but it's usually very inaccurate. So we'd rather advice him to
306159b3361Sopenharmony_ci                 * disable scaling first and see our suggestion on the scale factor then. */
307159b3361Sopenharmony_ci                console_printf("using --scale <arg>\n"
308159b3361Sopenharmony_ci                               "         (For   a   suggestion  on  the  optimal  value  of  <arg>  encode\n"
309159b3361Sopenharmony_ci                               "         with  --scale 1  first)\n");
310159b3361Sopenharmony_ci            }
311159b3361Sopenharmony_ci
312159b3361Sopenharmony_ci        }
313159b3361Sopenharmony_ci        else {          /* no clipping */
314159b3361Sopenharmony_ci            if (noclipGainChange > -0.1)
315159b3361Sopenharmony_ci                console_printf
316159b3361Sopenharmony_ci                    ("\nThe waveform does not clip and is less than 0.1dB away from full scale.\n");
317159b3361Sopenharmony_ci            else
318159b3361Sopenharmony_ci                console_printf
319159b3361Sopenharmony_ci                    ("\nThe waveform does not clip and is at least %.1fdB away from full scale.\n",
320159b3361Sopenharmony_ci                     -noclipGainChange);
321159b3361Sopenharmony_ci        }
322159b3361Sopenharmony_ci    }
323159b3361Sopenharmony_ci
324159b3361Sopenharmony_ci}
325159b3361Sopenharmony_ci
326159b3361Sopenharmony_ci
327159b3361Sopenharmony_cistatic int
328159b3361Sopenharmony_ciwrite_xing_frame(lame_global_flags * gf, FILE * outf, size_t offset)
329159b3361Sopenharmony_ci{
330159b3361Sopenharmony_ci    unsigned char mp3buffer[LAME_MAXMP3BUFFER];
331159b3361Sopenharmony_ci    size_t  imp3, owrite;
332159b3361Sopenharmony_ci
333159b3361Sopenharmony_ci    imp3 = lame_get_lametag_frame(gf, mp3buffer, sizeof(mp3buffer));
334159b3361Sopenharmony_ci    if (imp3 == 0) {
335159b3361Sopenharmony_ci        return 0;       /* nothing to do */
336159b3361Sopenharmony_ci    }
337159b3361Sopenharmony_ci    if (global_ui_config.silent <= 0) {
338159b3361Sopenharmony_ci        console_printf("Writing LAME Tag...");
339159b3361Sopenharmony_ci    }
340159b3361Sopenharmony_ci    if (imp3 > sizeof(mp3buffer)) {
341159b3361Sopenharmony_ci        error_printf
342159b3361Sopenharmony_ci            ("Error writing LAME-tag frame: buffer too small: buffer size=%d  frame size=%d\n",
343159b3361Sopenharmony_ci             sizeof(mp3buffer), imp3);
344159b3361Sopenharmony_ci        return -1;
345159b3361Sopenharmony_ci    }
346159b3361Sopenharmony_ci    assert( offset <= LONG_MAX );
347159b3361Sopenharmony_ci    if (fseek(outf, (long) offset, SEEK_SET) != 0) {
348159b3361Sopenharmony_ci        error_printf("fatal error: can't update LAME-tag frame!\n");
349159b3361Sopenharmony_ci        return -1;
350159b3361Sopenharmony_ci    }
351159b3361Sopenharmony_ci    owrite = fwrite(mp3buffer, 1, imp3, outf);
352159b3361Sopenharmony_ci    if (owrite != imp3) {
353159b3361Sopenharmony_ci        error_printf("Error writing LAME-tag \n");
354159b3361Sopenharmony_ci        return -1;
355159b3361Sopenharmony_ci    }
356159b3361Sopenharmony_ci    if (global_ui_config.silent <= 0) {
357159b3361Sopenharmony_ci        console_printf("done\n");
358159b3361Sopenharmony_ci    }
359159b3361Sopenharmony_ci    assert( imp3 <= INT_MAX );
360159b3361Sopenharmony_ci    return (int) imp3;
361159b3361Sopenharmony_ci}
362159b3361Sopenharmony_ci
363159b3361Sopenharmony_ci
364159b3361Sopenharmony_cistatic int
365159b3361Sopenharmony_ciwrite_id3v1_tag(lame_t gf, FILE * outf)
366159b3361Sopenharmony_ci{
367159b3361Sopenharmony_ci    unsigned char mp3buffer[128];
368159b3361Sopenharmony_ci    size_t  imp3, owrite;
369159b3361Sopenharmony_ci
370159b3361Sopenharmony_ci    imp3 = lame_get_id3v1_tag(gf, mp3buffer, sizeof(mp3buffer));
371159b3361Sopenharmony_ci    if (imp3 == 0) {
372159b3361Sopenharmony_ci        return 0;
373159b3361Sopenharmony_ci    }
374159b3361Sopenharmony_ci    if (imp3 > sizeof(mp3buffer)) {
375159b3361Sopenharmony_ci        error_printf("Error writing ID3v1 tag: buffer too small: buffer size=%d  ID3v1 size=%d\n",
376159b3361Sopenharmony_ci                     sizeof(mp3buffer), imp3);
377159b3361Sopenharmony_ci        return 0;       /* not critical */
378159b3361Sopenharmony_ci    }
379159b3361Sopenharmony_ci    owrite = fwrite(mp3buffer, 1, imp3, outf);
380159b3361Sopenharmony_ci    if (owrite != imp3) {
381159b3361Sopenharmony_ci        error_printf("Error writing ID3v1 tag \n");
382159b3361Sopenharmony_ci        return 1;
383159b3361Sopenharmony_ci    }
384159b3361Sopenharmony_ci    return 0;
385159b3361Sopenharmony_ci}
386159b3361Sopenharmony_ci
387159b3361Sopenharmony_ci
388159b3361Sopenharmony_cistatic int
389159b3361Sopenharmony_cilame_encoder_loop(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
390159b3361Sopenharmony_ci{
391159b3361Sopenharmony_ci    unsigned char mp3buffer[LAME_MAXMP3BUFFER];
392159b3361Sopenharmony_ci    int     Buffer[2][1152];
393159b3361Sopenharmony_ci    int     iread, imp3, owrite, in_limit=0;
394159b3361Sopenharmony_ci    size_t  id3v2_size;
395159b3361Sopenharmony_ci
396159b3361Sopenharmony_ci    encoder_progress_begin(gf, inPath, outPath);
397159b3361Sopenharmony_ci
398159b3361Sopenharmony_ci    id3v2_size = lame_get_id3v2_tag(gf, 0, 0);
399159b3361Sopenharmony_ci    if (id3v2_size > 0) {
400159b3361Sopenharmony_ci        unsigned char *id3v2tag = malloc(id3v2_size);
401159b3361Sopenharmony_ci        if (id3v2tag != 0) {
402159b3361Sopenharmony_ci            size_t  n_bytes = lame_get_id3v2_tag(gf, id3v2tag, id3v2_size);
403159b3361Sopenharmony_ci            size_t  written = fwrite(id3v2tag, 1, n_bytes, outf);
404159b3361Sopenharmony_ci            free(id3v2tag);
405159b3361Sopenharmony_ci            if (written != n_bytes) {
406159b3361Sopenharmony_ci                encoder_progress_end(gf);
407159b3361Sopenharmony_ci                error_printf("Error writing ID3v2 tag \n");
408159b3361Sopenharmony_ci                return 1;
409159b3361Sopenharmony_ci            }
410159b3361Sopenharmony_ci        }
411159b3361Sopenharmony_ci    }
412159b3361Sopenharmony_ci    else {
413159b3361Sopenharmony_ci        unsigned char* id3v2tag = getOldTag(gf);
414159b3361Sopenharmony_ci        id3v2_size = sizeOfOldTag(gf);
415159b3361Sopenharmony_ci        if ( id3v2_size > 0 ) {
416159b3361Sopenharmony_ci            size_t owrite = fwrite(id3v2tag, 1, id3v2_size, outf);
417159b3361Sopenharmony_ci            if (owrite != id3v2_size) {
418159b3361Sopenharmony_ci                encoder_progress_end(gf);
419159b3361Sopenharmony_ci                error_printf("Error writing ID3v2 tag \n");
420159b3361Sopenharmony_ci                return 1;
421159b3361Sopenharmony_ci            }
422159b3361Sopenharmony_ci        }
423159b3361Sopenharmony_ci    }
424159b3361Sopenharmony_ci    if (global_writer.flush_write == 1) {
425159b3361Sopenharmony_ci        fflush(outf);
426159b3361Sopenharmony_ci    }
427159b3361Sopenharmony_ci
428159b3361Sopenharmony_ci    /* do not feed more than in_limit PCM samples in one encode call
429159b3361Sopenharmony_ci       otherwise the mp3buffer is likely too small
430159b3361Sopenharmony_ci     */
431159b3361Sopenharmony_ci    in_limit = lame_get_maximum_number_of_samples(gf, sizeof(mp3buffer));
432159b3361Sopenharmony_ci    if (in_limit < 1)
433159b3361Sopenharmony_ci        in_limit = 1;
434159b3361Sopenharmony_ci
435159b3361Sopenharmony_ci    /* encode until we hit eof */
436159b3361Sopenharmony_ci    do {
437159b3361Sopenharmony_ci        /* read in 'iread' samples */
438159b3361Sopenharmony_ci        iread = get_audio(gf, Buffer);
439159b3361Sopenharmony_ci
440159b3361Sopenharmony_ci        if (iread >= 0) {
441159b3361Sopenharmony_ci            const int* buffer_l = Buffer[0];
442159b3361Sopenharmony_ci            const int* buffer_r = Buffer[1];
443159b3361Sopenharmony_ci            int     rest = iread;
444159b3361Sopenharmony_ci            do {
445159b3361Sopenharmony_ci                int const chunk = rest < in_limit ? rest : in_limit;
446159b3361Sopenharmony_ci                encoder_progress(gf);
447159b3361Sopenharmony_ci
448159b3361Sopenharmony_ci                /* encode */
449159b3361Sopenharmony_ci
450159b3361Sopenharmony_ci                imp3 = lame_encode_buffer_int(gf, buffer_l, buffer_r, chunk,
451159b3361Sopenharmony_ci                                              mp3buffer, sizeof(mp3buffer));
452159b3361Sopenharmony_ci                buffer_l += chunk;
453159b3361Sopenharmony_ci                buffer_r += chunk;
454159b3361Sopenharmony_ci                rest -= chunk;
455159b3361Sopenharmony_ci
456159b3361Sopenharmony_ci                /* was our output buffer big enough? */
457159b3361Sopenharmony_ci                if (imp3 < 0) {
458159b3361Sopenharmony_ci                    if (imp3 == -1)
459159b3361Sopenharmony_ci                        error_printf("mp3 buffer is not big enough... \n");
460159b3361Sopenharmony_ci                    else
461159b3361Sopenharmony_ci                        error_printf("mp3 internal error:  error code=%i\n", imp3);
462159b3361Sopenharmony_ci                    return 1;
463159b3361Sopenharmony_ci                }
464159b3361Sopenharmony_ci                owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
465159b3361Sopenharmony_ci                if (owrite != imp3) {
466159b3361Sopenharmony_ci                    error_printf("Error writing mp3 output \n");
467159b3361Sopenharmony_ci                    return 1;
468159b3361Sopenharmony_ci                }
469159b3361Sopenharmony_ci            } while (rest > 0);
470159b3361Sopenharmony_ci        }
471159b3361Sopenharmony_ci        if (global_writer.flush_write == 1) {
472159b3361Sopenharmony_ci            fflush(outf);
473159b3361Sopenharmony_ci        }
474159b3361Sopenharmony_ci    } while (iread > 0);
475159b3361Sopenharmony_ci
476159b3361Sopenharmony_ci    if (nogap)
477159b3361Sopenharmony_ci        imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
478159b3361Sopenharmony_ci    else
479159b3361Sopenharmony_ci        imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
480159b3361Sopenharmony_ci
481159b3361Sopenharmony_ci    if (imp3 < 0) {
482159b3361Sopenharmony_ci        if (imp3 == -1)
483159b3361Sopenharmony_ci            error_printf("mp3 buffer is not big enough... \n");
484159b3361Sopenharmony_ci        else
485159b3361Sopenharmony_ci            error_printf("mp3 internal error:  error code=%i\n", imp3);
486159b3361Sopenharmony_ci        return 1;
487159b3361Sopenharmony_ci
488159b3361Sopenharmony_ci    }
489159b3361Sopenharmony_ci
490159b3361Sopenharmony_ci    encoder_progress_end(gf);
491159b3361Sopenharmony_ci
492159b3361Sopenharmony_ci    owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
493159b3361Sopenharmony_ci    if (owrite != imp3) {
494159b3361Sopenharmony_ci        error_printf("Error writing mp3 output \n");
495159b3361Sopenharmony_ci        return 1;
496159b3361Sopenharmony_ci    }
497159b3361Sopenharmony_ci    if (global_writer.flush_write == 1) {
498159b3361Sopenharmony_ci        fflush(outf);
499159b3361Sopenharmony_ci    }
500159b3361Sopenharmony_ci    imp3 = write_id3v1_tag(gf, outf);
501159b3361Sopenharmony_ci    if (global_writer.flush_write == 1) {
502159b3361Sopenharmony_ci        fflush(outf);
503159b3361Sopenharmony_ci    }
504159b3361Sopenharmony_ci    if (imp3) {
505159b3361Sopenharmony_ci        return 1;
506159b3361Sopenharmony_ci    }
507159b3361Sopenharmony_ci    write_xing_frame(gf, outf, id3v2_size);
508159b3361Sopenharmony_ci    if (global_writer.flush_write == 1) {
509159b3361Sopenharmony_ci        fflush(outf);
510159b3361Sopenharmony_ci    }
511159b3361Sopenharmony_ci    if (global_ui_config.silent <= 0) {
512159b3361Sopenharmony_ci        print_trailing_info(gf);
513159b3361Sopenharmony_ci    }
514159b3361Sopenharmony_ci    return 0;
515159b3361Sopenharmony_ci}
516159b3361Sopenharmony_ci
517159b3361Sopenharmony_ci
518159b3361Sopenharmony_cistatic int
519159b3361Sopenharmony_cilame_encoder(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
520159b3361Sopenharmony_ci{
521159b3361Sopenharmony_ci    int     ret;
522159b3361Sopenharmony_ci
523159b3361Sopenharmony_ci    ret = lame_encoder_loop(gf, outf, nogap, inPath, outPath);
524159b3361Sopenharmony_ci    fclose(outf);       /* close the output file */
525159b3361Sopenharmony_ci    close_infile();     /* close the input file */
526159b3361Sopenharmony_ci    return ret;
527159b3361Sopenharmony_ci}
528159b3361Sopenharmony_ci
529159b3361Sopenharmony_ci
530159b3361Sopenharmony_ciint
531159b3361Sopenharmony_cilame_main(lame_t gf, int argc, char **argv)
532159b3361Sopenharmony_ci{
533159b3361Sopenharmony_ci    char    inPath[PATH_MAX + 1];
534159b3361Sopenharmony_ci    char    outPath[PATH_MAX + 1];
535159b3361Sopenharmony_ci    char    nogapdir[PATH_MAX + 1];
536159b3361Sopenharmony_ci    /* support for "nogap" encoding of up to 200 .wav files */
537159b3361Sopenharmony_ci#define MAX_NOGAP 200
538159b3361Sopenharmony_ci    int     nogapout = 0;
539159b3361Sopenharmony_ci    int     max_nogap = MAX_NOGAP;
540159b3361Sopenharmony_ci    char    nogap_inPath_[MAX_NOGAP][PATH_MAX + 1];
541159b3361Sopenharmony_ci    char   *nogap_inPath[MAX_NOGAP];
542159b3361Sopenharmony_ci    char    nogap_outPath_[MAX_NOGAP][PATH_MAX + 1];
543159b3361Sopenharmony_ci    char   *nogap_outPath[MAX_NOGAP];
544159b3361Sopenharmony_ci
545159b3361Sopenharmony_ci    int     ret;
546159b3361Sopenharmony_ci    int     i;
547159b3361Sopenharmony_ci    FILE   *outf = NULL;
548159b3361Sopenharmony_ci
549159b3361Sopenharmony_ci    lame_set_msgf(gf, &frontend_msgf);
550159b3361Sopenharmony_ci    lame_set_errorf(gf, &frontend_errorf);
551159b3361Sopenharmony_ci    lame_set_debugf(gf, &frontend_debugf);
552159b3361Sopenharmony_ci    if (argc <= 1) {
553159b3361Sopenharmony_ci        usage(stderr, argv[0]); /* no command-line args, print usage, exit  */
554159b3361Sopenharmony_ci        return 1;
555159b3361Sopenharmony_ci    }
556159b3361Sopenharmony_ci
557159b3361Sopenharmony_ci    memset(inPath, 0, sizeof(inPath));
558159b3361Sopenharmony_ci    memset(nogap_inPath_, 0, sizeof(nogap_inPath_));
559159b3361Sopenharmony_ci    for (i = 0; i < MAX_NOGAP; ++i) {
560159b3361Sopenharmony_ci        nogap_inPath[i] = &nogap_inPath_[i][0];
561159b3361Sopenharmony_ci    }
562159b3361Sopenharmony_ci    memset(nogap_outPath_, 0, sizeof(nogap_outPath_));
563159b3361Sopenharmony_ci    for (i = 0; i < MAX_NOGAP; ++i) {
564159b3361Sopenharmony_ci        nogap_outPath[i] = &nogap_outPath_[i][0];
565159b3361Sopenharmony_ci    }
566159b3361Sopenharmony_ci
567159b3361Sopenharmony_ci    /* parse the command line arguments, setting various flags in the
568159b3361Sopenharmony_ci     * struct 'gf'.  If you want to parse your own arguments,
569159b3361Sopenharmony_ci     * or call libmp3lame from a program which uses a GUI to set arguments,
570159b3361Sopenharmony_ci     * skip this call and set the values of interest in the gf struct.
571159b3361Sopenharmony_ci     * (see the file API and lame.h for documentation about these parameters)
572159b3361Sopenharmony_ci     */
573159b3361Sopenharmony_ci    ret = parse_args(gf, argc, argv, inPath, outPath, nogap_inPath, &max_nogap);
574159b3361Sopenharmony_ci    if (ret < 0) {
575159b3361Sopenharmony_ci        return ret == -2 ? 0 : 1;
576159b3361Sopenharmony_ci    }
577159b3361Sopenharmony_ci    if (global_ui_config.update_interval < 0.)
578159b3361Sopenharmony_ci        global_ui_config.update_interval = 2.;
579159b3361Sopenharmony_ci
580159b3361Sopenharmony_ci    if (outPath[0] != '\0' && max_nogap > 0) {
581159b3361Sopenharmony_ci        strncpy(nogapdir, outPath, PATH_MAX + 1);
582159b3361Sopenharmony_ci        nogapdir[PATH_MAX] = '\0';
583159b3361Sopenharmony_ci        nogapout = 1;
584159b3361Sopenharmony_ci    }
585159b3361Sopenharmony_ci
586159b3361Sopenharmony_ci    /* initialize input file.  This also sets samplerate and as much
587159b3361Sopenharmony_ci       other data on the input file as available in the headers */
588159b3361Sopenharmony_ci    if (max_nogap > 0) {
589159b3361Sopenharmony_ci          /* for nogap encoding of multiple input files, it is not possible to
590159b3361Sopenharmony_ci           * specify the output file name, only an optional output directory. */
591159b3361Sopenharmony_ci          for (i = 0; i < max_nogap; ++i) {
592159b3361Sopenharmony_ci              char const* outdir = nogapout ? nogapdir : "";
593159b3361Sopenharmony_ci              if (generateOutPath(nogap_inPath[i], outdir, ".mp3", nogap_outPath[i]) != 0) {
594159b3361Sopenharmony_ci                  error_printf("processing nogap file %d: %s\n", i+1, nogap_inPath[i]);
595159b3361Sopenharmony_ci                  return -1;
596159b3361Sopenharmony_ci              }
597159b3361Sopenharmony_ci          }
598159b3361Sopenharmony_ci          outf = init_files(gf, nogap_inPath[0], nogap_outPath[0]);
599159b3361Sopenharmony_ci    }
600159b3361Sopenharmony_ci    else {
601159b3361Sopenharmony_ci        outf = init_files(gf, inPath, outPath);
602159b3361Sopenharmony_ci    }
603159b3361Sopenharmony_ci    if (outf == NULL) {
604159b3361Sopenharmony_ci        close_infile();
605159b3361Sopenharmony_ci        return -1;
606159b3361Sopenharmony_ci    }
607159b3361Sopenharmony_ci    /* turn off automatic writing of ID3 tag data into mp3 stream
608159b3361Sopenharmony_ci     * we have to call it before 'lame_init_params', because that
609159b3361Sopenharmony_ci     * function would spit out ID3v2 tag data.
610159b3361Sopenharmony_ci     */
611159b3361Sopenharmony_ci    lame_set_write_id3tag_automatic(gf, 0);
612159b3361Sopenharmony_ci
613159b3361Sopenharmony_ci    /* Now that all the options are set, lame needs to analyze them and
614159b3361Sopenharmony_ci     * set some more internal options and check for problems
615159b3361Sopenharmony_ci     */
616159b3361Sopenharmony_ci    ret = lame_init_params(gf);
617159b3361Sopenharmony_ci    if (ret < 0) {
618159b3361Sopenharmony_ci        if (ret == -1) {
619159b3361Sopenharmony_ci            display_bitrates(stderr);
620159b3361Sopenharmony_ci        }
621159b3361Sopenharmony_ci        error_printf("fatal error during initialization\n");
622159b3361Sopenharmony_ci        fclose(outf);
623159b3361Sopenharmony_ci        close_infile();
624159b3361Sopenharmony_ci        return ret;
625159b3361Sopenharmony_ci    }
626159b3361Sopenharmony_ci
627159b3361Sopenharmony_ci    if (global_ui_config.silent > 0) {
628159b3361Sopenharmony_ci        global_ui_config.brhist = 0; /* turn off VBR histogram */
629159b3361Sopenharmony_ci    }
630159b3361Sopenharmony_ci
631159b3361Sopenharmony_ci    if (lame_get_decode_only(gf)) {
632159b3361Sopenharmony_ci        /* decode an mp3 file to a .wav */
633159b3361Sopenharmony_ci        ret = lame_decoder(gf, outf, inPath, outPath);
634159b3361Sopenharmony_ci    }
635159b3361Sopenharmony_ci    else if (max_nogap == 0) {
636159b3361Sopenharmony_ci        /* encode a single input file */
637159b3361Sopenharmony_ci        ret = lame_encoder(gf, outf, 0, inPath, outPath);
638159b3361Sopenharmony_ci    }
639159b3361Sopenharmony_ci    else {
640159b3361Sopenharmony_ci        /* encode multiple input files using nogap option */
641159b3361Sopenharmony_ci        for (i = 0; i < max_nogap; ++i) {
642159b3361Sopenharmony_ci            int     use_flush_nogap = (i != (max_nogap - 1));
643159b3361Sopenharmony_ci            if (i > 0) {
644159b3361Sopenharmony_ci                /* note: if init_files changes anything, like
645159b3361Sopenharmony_ci                   samplerate, num_channels, etc, we are screwed */
646159b3361Sopenharmony_ci                outf = init_files(gf, nogap_inPath[i], nogap_outPath[i]);
647159b3361Sopenharmony_ci                if (outf == NULL) {
648159b3361Sopenharmony_ci                    close_infile();
649159b3361Sopenharmony_ci                    return -1;
650159b3361Sopenharmony_ci                }
651159b3361Sopenharmony_ci                /* reinitialize bitstream for next encoding.  this is normally done
652159b3361Sopenharmony_ci                 * by lame_init_params(), but we cannot call that routine twice */
653159b3361Sopenharmony_ci                lame_init_bitstream(gf);
654159b3361Sopenharmony_ci            }
655159b3361Sopenharmony_ci            lame_set_nogap_total(gf, max_nogap);
656159b3361Sopenharmony_ci            lame_set_nogap_currentindex(gf, i);
657159b3361Sopenharmony_ci            ret = lame_encoder(gf, outf, use_flush_nogap, nogap_inPath[i], nogap_outPath[i]);
658159b3361Sopenharmony_ci        }
659159b3361Sopenharmony_ci    }
660159b3361Sopenharmony_ci    return ret;
661159b3361Sopenharmony_ci}
662