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