Blame frontend/lame_main.c

Packit 47f805
/*
Packit 47f805
 *      Command line frontend program
Packit 47f805
 *
Packit 47f805
 *      Copyright (c) 1999 Mark Taylor
Packit 47f805
 *                    2000 Takehiro TOMINAGA
Packit 47f805
 *                    2010-2017 Robert Hegemann
Packit 47f805
 *
Packit 47f805
 * This library is free software; you can redistribute it and/or
Packit 47f805
 * modify it under the terms of the GNU Library General Public
Packit 47f805
 * License as published by the Free Software Foundation; either
Packit 47f805
 * version 2 of the License, or (at your option) any later version.
Packit 47f805
 *
Packit 47f805
 * This library is distributed in the hope that it will be useful,
Packit 47f805
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 47f805
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 47f805
 * Library General Public License for more details.
Packit 47f805
 *
Packit 47f805
 * You should have received a copy of the GNU Library General Public
Packit 47f805
 * License along with this library; if not, write to the
Packit 47f805
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 47f805
 * Boston, MA 02111-1307, USA.
Packit 47f805
 */
Packit 47f805
Packit 47f805
/* $Id: lame_main.c,v 1.18 2017/08/31 14:14:46 robert Exp $ */
Packit 47f805
Packit 47f805
#ifdef HAVE_CONFIG_H
Packit 47f805
# include <config.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#include <assert.h>
Packit 47f805
#include <stdio.h>
Packit 47f805
Packit 47f805
#ifdef STDC_HEADERS
Packit 47f805
# include <stdlib.h>
Packit 47f805
# include <string.h>
Packit 47f805
#else
Packit 47f805
# ifndef HAVE_STRCHR
Packit 47f805
#  define strchr index
Packit 47f805
#  define strrchr rindex
Packit 47f805
# endif
Packit 47f805
char   *strchr(), *strrchr();
Packit 47f805
# ifndef HAVE_MEMCPY
Packit 47f805
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
Packit 47f805
#  define memmove(d, s, n) bcopy ((s), (d), (n))
Packit 47f805
# endif
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#ifdef HAVE_FCNTL_H
Packit 47f805
# include <fcntl.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#ifdef __sun__
Packit 47f805
/* woraround for SunOS 4.x, it has SEEK_* defined here */
Packit 47f805
#include <unistd.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#if defined(_WIN32)
Packit 47f805
# include <windows.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
Packit 47f805
/*
Packit 47f805
 main.c is example code for how to use libmp3lame.a.  To use this library,
Packit 47f805
 you only need the library and lame.h.  All other .h files are private
Packit 47f805
 to the library.
Packit 47f805
*/
Packit 47f805
#include "lame.h"
Packit 47f805
Packit 47f805
#include "console.h"
Packit 47f805
#include "parse.h"
Packit 47f805
#include "main.h"
Packit 47f805
#include "get_audio.h"
Packit 47f805
#include "timestatus.h"
Packit 47f805
Packit 47f805
/* PLL 14/04/2000 */
Packit 47f805
#if macintosh
Packit 47f805
#include <console.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#ifdef WITH_DMALLOC
Packit 47f805
#include <dmalloc.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
Packit 47f805
Packit 47f805
Packit 47f805
/************************************************************************
Packit 47f805
*
Packit 47f805
* main
Packit 47f805
*
Packit 47f805
* PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
Packit 47f805
* psychoacoustic model.
Packit 47f805
*
Packit 47f805
************************************************************************/
Packit 47f805
Packit 47f805
Packit 47f805
static FILE *
Packit 47f805
init_files(lame_global_flags * gf, char const *inPath, char const *outPath)
Packit 47f805
{
Packit 47f805
    FILE   *outf;
Packit 47f805
    /* Mostly it is not useful to use the same input and output name.
Packit 47f805
       This test is very easy and buggy and don't recognize different names
Packit 47f805
       assigning the same file
Packit 47f805
     */
Packit 47f805
    if (0 != strcmp("-", outPath) && 0 == strcmp(inPath, outPath)) {
Packit 47f805
        error_printf("Input file and Output file are the same. Abort.\n");
Packit 47f805
        return NULL;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* open the wav/aiff/raw pcm or mp3 input file.  This call will
Packit 47f805
     * open the file, try to parse the headers and
Packit 47f805
     * set gf.samplerate, gf.num_channels, gf.num_samples.
Packit 47f805
     * if you want to do your own file input, skip this call and set
Packit 47f805
     * samplerate, num_channels and num_samples yourself.
Packit 47f805
     */
Packit 47f805
    if (init_infile(gf, inPath) < 0) {
Packit 47f805
        error_printf("Can't init infile '%s'\n", inPath);
Packit 47f805
        return NULL;
Packit 47f805
    }
Packit 47f805
    if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
Packit 47f805
        error_printf("Can't init outfile '%s'\n", outPath);
Packit 47f805
        return NULL;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return outf;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static void
Packit 47f805
printInputFormat(lame_t gfp)
Packit 47f805
{
Packit 47f805
    int const v_main = 2 - lame_get_version(gfp);
Packit 47f805
    char const *v_ex = lame_get_out_samplerate(gfp) < 16000 ? ".5" : "";
Packit 47f805
    switch (global_reader.input_format) {
Packit 47f805
    case sf_mp123:     /* FIXME: !!! */
Packit 47f805
        break;
Packit 47f805
    case sf_mp3:
Packit 47f805
        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "III");
Packit 47f805
        break;
Packit 47f805
    case sf_mp2:
Packit 47f805
        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "II");
Packit 47f805
        break;
Packit 47f805
    case sf_mp1:
Packit 47f805
        console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "I");
Packit 47f805
        break;
Packit 47f805
    case sf_raw:
Packit 47f805
        console_printf("raw PCM data");
Packit 47f805
        break;
Packit 47f805
    case sf_wave:
Packit 47f805
        console_printf("Microsoft WAVE");
Packit 47f805
        break;
Packit 47f805
    case sf_aiff:
Packit 47f805
        console_printf("SGI/Apple AIFF");
Packit 47f805
        break;
Packit 47f805
    default:
Packit 47f805
        console_printf("unknown");
Packit 47f805
        break;
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
/* the simple lame decoder */
Packit 47f805
/* After calling lame_init(), lame_init_params() and
Packit 47f805
 * init_infile(), call this routine to read the input MP3 file
Packit 47f805
 * and output .wav data to the specified file pointer*/
Packit 47f805
/* lame_decoder will ignore the first 528 samples, since these samples
Packit 47f805
 * represent the mpglib delay (and are all 0).  skip = number of additional
Packit 47f805
 * samples to skip, to (for example) compensate for the encoder delay */
Packit 47f805
Packit 47f805
static int
Packit 47f805
lame_decoder_loop(lame_t gfp, FILE * outf, char *inPath, char *outPath)
Packit 47f805
{
Packit 47f805
    short int Buffer[2][1152];
Packit 47f805
    int     i, iread;
Packit 47f805
    double  wavsize;
Packit 47f805
    int     tmp_num_channels = lame_get_num_channels(gfp);
Packit 47f805
    int     skip_start = samples_to_skip_at_start();
Packit 47f805
    int     skip_end = samples_to_skip_at_end();
Packit 47f805
    DecoderProgress dp = 0;
Packit 47f805
Packit 47f805
    if (!(tmp_num_channels >= 1 && tmp_num_channels <= 2)) {
Packit 47f805
        error_printf("Internal error.  Aborting.");
Packit 47f805
        return -1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (global_ui_config.silent < 9) {
Packit 47f805
        console_printf("\rinput:  %s%s(%g kHz, %i channel%s, ",
Packit 47f805
                       strcmp(inPath, "-") ? inPath : "<stdin>",
Packit 47f805
                       strlen(inPath) > 26 ? "\n\t" : "  ",
Packit 47f805
                       lame_get_in_samplerate(gfp) / 1.e3,
Packit 47f805
                       tmp_num_channels, tmp_num_channels != 1 ? "s" : "");
Packit 47f805
Packit 47f805
        printInputFormat(gfp);
Packit 47f805
Packit 47f805
        console_printf(")\noutput: %s%s(16 bit, Microsoft WAVE)\n",
Packit 47f805
                       strcmp(outPath, "-") ? outPath : "<stdout>",
Packit 47f805
                       strlen(outPath) > 45 ? "\n\t" : "  ");
Packit 47f805
Packit 47f805
        if (skip_start > 0)
Packit 47f805
            console_printf("skipping initial %i samples (encoder+decoder delay)\n", skip_start);
Packit 47f805
        if (skip_end > 0)
Packit 47f805
            console_printf("skipping final %i samples (encoder padding-decoder delay)\n", skip_end);
Packit 47f805
Packit 47f805
        switch (global_reader.input_format) {
Packit 47f805
        case sf_mp3:
Packit 47f805
        case sf_mp2:
Packit 47f805
        case sf_mp1:
Packit 47f805
            dp = decoder_progress_init(lame_get_num_samples(gfp),
Packit 47f805
                                       global_decoder.mp3input_data.framesize);
Packit 47f805
            break;
Packit 47f805
        case sf_raw:
Packit 47f805
        case sf_wave:
Packit 47f805
        case sf_aiff:
Packit 47f805
        default:
Packit 47f805
            dp = decoder_progress_init(lame_get_num_samples(gfp),
Packit 47f805
                                       lame_get_in_samplerate(gfp) < 32000 ? 576 : 1152);
Packit 47f805
            break;
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (0 == global_decoder.disable_wav_header)
Packit 47f805
        WriteWaveHeader(outf, 0x7FFFFFFF, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
Packit 47f805
    /* unknown size, so write maximum 32 bit signed value */
Packit 47f805
Packit 47f805
    wavsize = 0;
Packit 47f805
    do {
Packit 47f805
        iread = get_audio16(gfp, Buffer); /* read in 'iread' samples */
Packit 47f805
        if (iread >= 0) {
Packit 47f805
            wavsize += iread;
Packit 47f805
            if (dp != 0) {
Packit 47f805
                decoder_progress(dp, &global_decoder.mp3input_data, iread);
Packit 47f805
            }
Packit 47f805
            put_audio16(outf, Buffer, iread, tmp_num_channels);
Packit 47f805
        }
Packit 47f805
    } while (iread > 0);
Packit 47f805
Packit 47f805
    i = (16 / 8) * tmp_num_channels;
Packit 47f805
    assert(i > 0);
Packit 47f805
    if (wavsize <= 0) {
Packit 47f805
        if (global_ui_config.silent < 10)
Packit 47f805
            error_printf("WAVE file contains 0 PCM samples\n");
Packit 47f805
        wavsize = 0;
Packit 47f805
    }
Packit 47f805
    else if (wavsize > 0xFFFFFFD0 / i) {
Packit 47f805
        if (global_ui_config.silent < 10)
Packit 47f805
            error_printf("Very huge WAVE file, can't set filesize accordingly\n");
Packit 47f805
        wavsize = 0xFFFFFFD0;
Packit 47f805
    }
Packit 47f805
    else {
Packit 47f805
        wavsize *= i;
Packit 47f805
    }
Packit 47f805
    /* if outf is seekable, rewind and adjust length */
Packit 47f805
    if (!global_decoder.disable_wav_header && strcmp("-", outPath)
Packit 47f805
        && !fseek(outf, 0l, SEEK_SET))
Packit 47f805
        WriteWaveHeader(outf, (int) wavsize, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
Packit 47f805
Packit 47f805
    if (dp != 0)
Packit 47f805
        decoder_progress_finish(dp);
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
static int
Packit 47f805
lame_decoder(lame_t gfp, FILE * outf, char *inPath, char *outPath)
Packit 47f805
{
Packit 47f805
    int     ret;
Packit 47f805
Packit 47f805
    ret = lame_decoder_loop(gfp, outf, inPath, outPath);
Packit 47f805
    fclose(outf);       /* close the output file */
Packit 47f805
    close_infile();     /* close the input file */
Packit 47f805
    return ret;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static void
Packit 47f805
print_trailing_info(lame_global_flags * gf)
Packit 47f805
{
Packit 47f805
    if (lame_get_findReplayGain(gf)) {
Packit 47f805
        int     RadioGain = lame_get_RadioGain(gf);
Packit 47f805
        console_printf("ReplayGain: %s%.1fdB\n", RadioGain > 0 ? "+" : "",
Packit 47f805
                       ((float) RadioGain) / 10.0);
Packit 47f805
        if (RadioGain > 0x1FE || RadioGain < -0x1FE)
Packit 47f805
            error_printf
Packit 47f805
                ("WARNING: ReplayGain exceeds the -51dB to +51dB range. Such a result is too\n"
Packit 47f805
                 "         high to be stored in the header.\n");
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* if (the user requested printing info about clipping) and (decoding
Packit 47f805
       on the fly has actually been performed) */
Packit 47f805
    if (global_ui_config.print_clipping_info && lame_get_decode_on_the_fly(gf)) {
Packit 47f805
        float   noclipGainChange = (float) lame_get_noclipGainChange(gf) / 10.0f;
Packit 47f805
        float   noclipScale = lame_get_noclipScale(gf);
Packit 47f805
Packit 47f805
        if (noclipGainChange > 0.0) { /* clipping occurs */
Packit 47f805
            console_printf
Packit 47f805
                ("WARNING: clipping occurs at the current gain. Set your decoder to decrease\n"
Packit 47f805
                 "         the  gain  by  at least %.1fdB or encode again ", noclipGainChange);
Packit 47f805
Packit 47f805
            /* advice the user on the scale factor */
Packit 47f805
            if (noclipScale > 0) {
Packit 47f805
                console_printf("using  --scale %.2f\n", noclipScale * lame_get_scale(gf));
Packit 47f805
                console_printf("         or less (the value under --scale is approximate).\n");
Packit 47f805
            }
Packit 47f805
            else {
Packit 47f805
                /* the user specified his own scale factor. We could suggest
Packit 47f805
                 * the scale factor of (32767.0/gfp->PeakSample)*(gfp->scale)
Packit 47f805
                 * but it's usually very inaccurate. So we'd rather advice him to
Packit 47f805
                 * disable scaling first and see our suggestion on the scale factor then. */
Packit 47f805
                console_printf("using --scale <arg>\n"
Packit 47f805
                               "         (For   a   suggestion  on  the  optimal  value  of  <arg>  encode\n"
Packit 47f805
                               "         with  --scale 1  first)\n");
Packit 47f805
            }
Packit 47f805
Packit 47f805
        }
Packit 47f805
        else {          /* no clipping */
Packit 47f805
            if (noclipGainChange > -0.1)
Packit 47f805
                console_printf
Packit 47f805
                    ("\nThe waveform does not clip and is less than 0.1dB away from full scale.\n");
Packit 47f805
            else
Packit 47f805
                console_printf
Packit 47f805
                    ("\nThe waveform does not clip and is at least %.1fdB away from full scale.\n",
Packit 47f805
                     -noclipGainChange);
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static int
Packit 47f805
write_xing_frame(lame_global_flags * gf, FILE * outf, size_t offset)
Packit 47f805
{
Packit 47f805
    unsigned char mp3buffer[LAME_MAXMP3BUFFER];
Packit 47f805
    size_t  imp3, owrite;
Packit 47f805
Packit 47f805
    imp3 = lame_get_lametag_frame(gf, mp3buffer, sizeof(mp3buffer));
Packit 47f805
    if (imp3 <= 0) {
Packit 47f805
        return 0;       /* nothing to do */
Packit 47f805
    }
Packit 47f805
    if (global_ui_config.silent <= 0) {
Packit 47f805
        console_printf("Writing LAME Tag...");
Packit 47f805
    }
Packit 47f805
    if (imp3 > sizeof(mp3buffer)) {
Packit 47f805
        error_printf
Packit 47f805
            ("Error writing LAME-tag frame: buffer too small: buffer size=%d  frame size=%d\n",
Packit 47f805
             sizeof(mp3buffer), imp3);
Packit 47f805
        return -1;
Packit 47f805
    }
Packit 47f805
    assert( offset <= LONG_MAX );
Packit 47f805
    if (fseek(outf, (long) offset, SEEK_SET) != 0) {
Packit 47f805
        error_printf("fatal error: can't update LAME-tag frame!\n");
Packit 47f805
        return -1;
Packit 47f805
    }
Packit 47f805
    owrite = fwrite(mp3buffer, 1, imp3, outf);
Packit 47f805
    if (owrite != imp3) {
Packit 47f805
        error_printf("Error writing LAME-tag \n");
Packit 47f805
        return -1;
Packit 47f805
    }
Packit 47f805
    if (global_ui_config.silent <= 0) {
Packit 47f805
        console_printf("done\n");
Packit 47f805
    }
Packit 47f805
    assert( imp3 <= INT_MAX );
Packit 47f805
    return (int) imp3;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static int
Packit 47f805
write_id3v1_tag(lame_t gf, FILE * outf)
Packit 47f805
{
Packit 47f805
    unsigned char mp3buffer[128];
Packit 47f805
    size_t  imp3, owrite;
Packit 47f805
Packit 47f805
    imp3 = lame_get_id3v1_tag(gf, mp3buffer, sizeof(mp3buffer));
Packit 47f805
    if (imp3 <= 0) {
Packit 47f805
        return 0;
Packit 47f805
    }
Packit 47f805
    if (imp3 > sizeof(mp3buffer)) {
Packit 47f805
        error_printf("Error writing ID3v1 tag: buffer too small: buffer size=%d  ID3v1 size=%d\n",
Packit 47f805
                     sizeof(mp3buffer), imp3);
Packit 47f805
        return 0;       /* not critical */
Packit 47f805
    }
Packit 47f805
    owrite = fwrite(mp3buffer, 1, imp3, outf);
Packit 47f805
    if (owrite != imp3) {
Packit 47f805
        error_printf("Error writing ID3v1 tag \n");
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static int
Packit 47f805
lame_encoder_loop(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
Packit 47f805
{
Packit 47f805
    unsigned char mp3buffer[LAME_MAXMP3BUFFER];
Packit 47f805
    int     Buffer[2][1152];
Packit 47f805
    int     iread, imp3, owrite, in_limit=0;
Packit 47f805
    size_t  id3v2_size;
Packit 47f805
Packit 47f805
    encoder_progress_begin(gf, inPath, outPath);
Packit 47f805
Packit 47f805
    id3v2_size = lame_get_id3v2_tag(gf, 0, 0);
Packit 47f805
    if (id3v2_size > 0) {
Packit 47f805
        unsigned char *id3v2tag = malloc(id3v2_size);
Packit 47f805
        if (id3v2tag != 0) {
Packit 47f805
            size_t  n_bytes = lame_get_id3v2_tag(gf, id3v2tag, id3v2_size);
Packit 47f805
            size_t  written = fwrite(id3v2tag, 1, n_bytes, outf);
Packit 47f805
            free(id3v2tag);
Packit 47f805
            if (written != n_bytes) {
Packit 47f805
                encoder_progress_end(gf);
Packit 47f805
                error_printf("Error writing ID3v2 tag \n");
Packit 47f805
                return 1;
Packit 47f805
            }
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    else {
Packit 47f805
        unsigned char* id3v2tag = getOldTag(gf);
Packit 47f805
        id3v2_size = sizeOfOldTag(gf);
Packit 47f805
        if ( id3v2_size > 0 ) {
Packit 47f805
            size_t owrite = fwrite(id3v2tag, 1, id3v2_size, outf);
Packit 47f805
            if (owrite != id3v2_size) {
Packit 47f805
                encoder_progress_end(gf);
Packit 47f805
                error_printf("Error writing ID3v2 tag \n");
Packit 47f805
                return 1;
Packit 47f805
            }
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    if (global_writer.flush_write == 1) {
Packit 47f805
        fflush(outf);
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* do not feed more than in_limit PCM samples in one encode call
Packit 47f805
       otherwise the mp3buffer is likely too small
Packit 47f805
     */
Packit 47f805
    in_limit = lame_get_maximum_number_of_samples(gf, sizeof(mp3buffer));
Packit 47f805
    if (in_limit < 1)
Packit 47f805
        in_limit = 1;
Packit 47f805
Packit 47f805
    /* encode until we hit eof */
Packit 47f805
    do {
Packit 47f805
        /* read in 'iread' samples */
Packit 47f805
        iread = get_audio(gf, Buffer);
Packit 47f805
Packit 47f805
        if (iread >= 0) {
Packit 47f805
            const int* buffer_l = Buffer[0];
Packit 47f805
            const int* buffer_r = Buffer[1];
Packit 47f805
            int     rest = iread;
Packit 47f805
            do {
Packit 47f805
                int const chunk = rest < in_limit ? rest : in_limit;
Packit 47f805
                encoder_progress(gf);
Packit 47f805
Packit 47f805
                /* encode */
Packit 47f805
Packit 47f805
                imp3 = lame_encode_buffer_int(gf, buffer_l, buffer_r, chunk,
Packit 47f805
                                              mp3buffer, sizeof(mp3buffer));
Packit 47f805
                buffer_l += chunk;
Packit 47f805
                buffer_r += chunk;
Packit 47f805
                rest -= chunk;
Packit 47f805
Packit 47f805
                /* was our output buffer big enough? */
Packit 47f805
                if (imp3 < 0) {
Packit 47f805
                    if (imp3 == -1)
Packit 47f805
                        error_printf("mp3 buffer is not big enough... \n");
Packit 47f805
                    else
Packit 47f805
                        error_printf("mp3 internal error:  error code=%i\n", imp3);
Packit 47f805
                    return 1;
Packit 47f805
                }
Packit 47f805
                owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
Packit 47f805
                if (owrite != imp3) {
Packit 47f805
                    error_printf("Error writing mp3 output \n");
Packit 47f805
                    return 1;
Packit 47f805
                }
Packit 47f805
            } while (rest > 0);
Packit 47f805
        }
Packit 47f805
        if (global_writer.flush_write == 1) {
Packit 47f805
            fflush(outf);
Packit 47f805
        }
Packit 47f805
    } while (iread > 0);
Packit 47f805
Packit 47f805
    if (nogap)
Packit 47f805
        imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
Packit 47f805
    else
Packit 47f805
        imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
Packit 47f805
Packit 47f805
    if (imp3 < 0) {
Packit 47f805
        if (imp3 == -1)
Packit 47f805
            error_printf("mp3 buffer is not big enough... \n");
Packit 47f805
        else
Packit 47f805
            error_printf("mp3 internal error:  error code=%i\n", imp3);
Packit 47f805
        return 1;
Packit 47f805
Packit 47f805
    }
Packit 47f805
Packit 47f805
    encoder_progress_end(gf);
Packit 47f805
Packit 47f805
    owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
Packit 47f805
    if (owrite != imp3) {
Packit 47f805
        error_printf("Error writing mp3 output \n");
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
    if (global_writer.flush_write == 1) {
Packit 47f805
        fflush(outf);
Packit 47f805
    }
Packit 47f805
    imp3 = write_id3v1_tag(gf, outf);
Packit 47f805
    if (global_writer.flush_write == 1) {
Packit 47f805
        fflush(outf);
Packit 47f805
    }
Packit 47f805
    if (imp3) {
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
    write_xing_frame(gf, outf, id3v2_size);
Packit 47f805
    if (global_writer.flush_write == 1) {
Packit 47f805
        fflush(outf);
Packit 47f805
    }
Packit 47f805
    if (global_ui_config.silent <= 0) {
Packit 47f805
        print_trailing_info(gf);
Packit 47f805
    }
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static int
Packit 47f805
lame_encoder(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
Packit 47f805
{
Packit 47f805
    int     ret;
Packit 47f805
Packit 47f805
    ret = lame_encoder_loop(gf, outf, nogap, inPath, outPath);
Packit 47f805
    fclose(outf);       /* close the output file */
Packit 47f805
    close_infile();     /* close the input file */
Packit 47f805
    return ret;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int
Packit 47f805
lame_main(lame_t gf, int argc, char **argv)
Packit 47f805
{
Packit 47f805
    char    inPath[PATH_MAX + 1];
Packit 47f805
    char    outPath[PATH_MAX + 1];
Packit 47f805
    char    nogapdir[PATH_MAX + 1];
Packit 47f805
    /* support for "nogap" encoding of up to 200 .wav files */
Packit 47f805
#define MAX_NOGAP 200
Packit 47f805
    int     nogapout = 0;
Packit 47f805
    int     max_nogap = MAX_NOGAP;
Packit 47f805
    char    nogap_inPath_[MAX_NOGAP][PATH_MAX + 1];
Packit 47f805
    char   *nogap_inPath[MAX_NOGAP];
Packit 47f805
    char    nogap_outPath_[MAX_NOGAP][PATH_MAX + 1];
Packit 47f805
    char   *nogap_outPath[MAX_NOGAP];
Packit 47f805
Packit 47f805
    int     ret;
Packit 47f805
    int     i;
Packit 47f805
    FILE   *outf = NULL;
Packit 47f805
Packit 47f805
    lame_set_msgf(gf, &frontend_msgf);
Packit 47f805
    lame_set_errorf(gf, &frontend_errorf);
Packit 47f805
    lame_set_debugf(gf, &frontend_debugf);
Packit 47f805
    if (argc <= 1) {
Packit 47f805
        usage(stderr, argv[0]); /* no command-line args, print usage, exit  */
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    memset(inPath, 0, sizeof(inPath));
Packit 47f805
    memset(nogap_inPath_, 0, sizeof(nogap_inPath_));
Packit 47f805
    for (i = 0; i < MAX_NOGAP; ++i) {
Packit 47f805
        nogap_inPath[i] = &nogap_inPath_[i][0];
Packit 47f805
    }
Packit 47f805
    memset(nogap_outPath_, 0, sizeof(nogap_outPath_));
Packit 47f805
    for (i = 0; i < MAX_NOGAP; ++i) {
Packit 47f805
        nogap_outPath[i] = &nogap_outPath_[i][0];
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* parse the command line arguments, setting various flags in the
Packit 47f805
     * struct 'gf'.  If you want to parse your own arguments,
Packit 47f805
     * or call libmp3lame from a program which uses a GUI to set arguments,
Packit 47f805
     * skip this call and set the values of interest in the gf struct.
Packit 47f805
     * (see the file API and lame.h for documentation about these parameters)
Packit 47f805
     */
Packit 47f805
    ret = parse_args(gf, argc, argv, inPath, outPath, nogap_inPath, &max_nogap);
Packit 47f805
    if (ret < 0) {
Packit 47f805
        return ret == -2 ? 0 : 1;
Packit 47f805
    }
Packit 47f805
    if (global_ui_config.update_interval < 0.)
Packit 47f805
        global_ui_config.update_interval = 2.;
Packit 47f805
Packit 47f805
    if (outPath[0] != '\0' && max_nogap > 0) {
Packit 47f805
        strncpy(nogapdir, outPath, PATH_MAX + 1);
Packit 47f805
        nogapdir[PATH_MAX] = '\0';
Packit 47f805
        nogapout = 1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* initialize input file.  This also sets samplerate and as much
Packit 47f805
       other data on the input file as available in the headers */
Packit 47f805
    if (max_nogap > 0) {
Packit 47f805
          /* for nogap encoding of multiple input files, it is not possible to
Packit 47f805
           * specify the output file name, only an optional output directory. */
Packit 47f805
          for (i = 0; i < max_nogap; ++i) {
Packit 47f805
              char const* outdir = nogapout ? nogapdir : "";
Packit 47f805
              if (generateOutPath(nogap_inPath[i], outdir, ".mp3", nogap_outPath[i]) != 0) {
Packit 47f805
                  error_printf("processing nogap file %d: %s\n", i+1, nogap_inPath[i]);
Packit 47f805
                  return -1;
Packit 47f805
              }
Packit 47f805
          }
Packit 47f805
          outf = init_files(gf, nogap_inPath[0], nogap_outPath[0]);
Packit 47f805
    }
Packit 47f805
    else {
Packit 47f805
        outf = init_files(gf, inPath, outPath);
Packit 47f805
    }
Packit 47f805
    if (outf == NULL) {
Packit 47f805
        close_infile();
Packit 47f805
        return -1;
Packit 47f805
    }
Packit 47f805
    /* turn off automatic writing of ID3 tag data into mp3 stream 
Packit 47f805
     * we have to call it before 'lame_init_params', because that
Packit 47f805
     * function would spit out ID3v2 tag data.
Packit 47f805
     */
Packit 47f805
    lame_set_write_id3tag_automatic(gf, 0);
Packit 47f805
Packit 47f805
    /* Now that all the options are set, lame needs to analyze them and
Packit 47f805
     * set some more internal options and check for problems
Packit 47f805
     */
Packit 47f805
    ret = lame_init_params(gf);
Packit 47f805
    if (ret < 0) {
Packit 47f805
        if (ret == -1) {
Packit 47f805
            display_bitrates(stderr);
Packit 47f805
        }
Packit 47f805
        error_printf("fatal error during initialization\n");
Packit 47f805
        fclose(outf);
Packit 47f805
        close_infile();
Packit 47f805
        return ret;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (global_ui_config.silent > 0) {
Packit 47f805
        global_ui_config.brhist = 0; /* turn off VBR histogram */
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (lame_get_decode_only(gf)) {
Packit 47f805
        /* decode an mp3 file to a .wav */
Packit 47f805
        ret = lame_decoder(gf, outf, inPath, outPath);
Packit 47f805
    }
Packit 47f805
    else if (max_nogap == 0) {
Packit 47f805
        /* encode a single input file */
Packit 47f805
        ret = lame_encoder(gf, outf, 0, inPath, outPath);
Packit 47f805
    }
Packit 47f805
    else {
Packit 47f805
        /* encode multiple input files using nogap option */
Packit 47f805
        for (i = 0; i < max_nogap; ++i) {
Packit 47f805
            int     use_flush_nogap = (i != (max_nogap - 1));
Packit 47f805
            if (i > 0) {
Packit 47f805
                /* note: if init_files changes anything, like
Packit 47f805
                   samplerate, num_channels, etc, we are screwed */
Packit 47f805
                outf = init_files(gf, nogap_inPath[i], nogap_outPath[i]);
Packit 47f805
                if (outf == NULL) {
Packit 47f805
                    close_infile();
Packit 47f805
                    return -1;
Packit 47f805
                }
Packit 47f805
                /* reinitialize bitstream for next encoding.  this is normally done
Packit 47f805
                 * by lame_init_params(), but we cannot call that routine twice */
Packit 47f805
                lame_init_bitstream(gf);
Packit 47f805
            }
Packit 47f805
            lame_set_nogap_total(gf, max_nogap);
Packit 47f805
            lame_set_nogap_currentindex(gf, i);
Packit 47f805
            ret = lame_encoder(gf, outf, use_flush_nogap, nogap_inPath[i], nogap_outPath[i]);
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    return ret;
Packit 47f805
}