OSDN Git Service

wwww
[proj16/16.git] / src / lib / doslib / ext / lame / lame_main.c
1 /*
2  *      Command line frontend program
3  *
4  *      Copyright (c) 1999 Mark Taylor
5  *                    2000 Takehiro TOMINAGA
6  *                    2010-2011 Robert Hegemann
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* $Id: lame_main.c,v 1.9.2.1 2011/11/18 08:38:04 robert Exp $ */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <assert.h>
31 #include <stdio.h>
32
33 #ifdef STDC_HEADERS
34 # include <stdlib.h>
35 # include <string.h>
36 #else
37 # ifndef HAVE_STRCHR
38 #  define strchr index
39 #  define strrchr rindex
40 # endif
41 char   *strchr(), *strrchr();
42 # ifndef HAVE_MEMCPY
43 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
44 #  define memmove(d, s, n) bcopy ((s), (d), (n))
45 # endif
46 #endif
47
48 #ifdef HAVE_FCNTL_H
49 # include <fcntl.h>
50 #endif
51
52 #ifdef __sun__
53 /* woraround for SunOS 4.x, it has SEEK_* defined here */
54 #include <unistd.h>
55 #endif
56
57 #if defined(_WIN32)
58 # include <windows.h>
59 #endif
60
61
62 /*
63  main.c is example code for how to use libmp3lame.a.  To use this library,
64  you only need the library and lame.h.  All other .h files are private
65  to the library.
66 */
67 #include "lame.h"
68
69 #include "console.h"
70 #include "parse.h"
71 #include "main.h"
72 #include "get_audio.h"
73 #include "timestatus.h"
74
75 /* PLL 14/04/2000 */
76 #if macintosh
77 #include <console.h>
78 #endif
79
80 #ifdef WITH_DMALLOC
81 #include <dmalloc.h>
82 #endif
83
84
85
86
87 /************************************************************************
88 *
89 * main
90 *
91 * PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
92 * psychoacoustic model.
93 *
94 ************************************************************************/
95
96
97 static int
98 parse_args_from_string(lame_global_flags * const gfp, const char *p, char *inPath, char *outPath)
99 {                       /* Quick & very Dirty */
100     char   *q;
101     char   *f;
102     char   *r[128];
103     int     c = 0;
104     int     ret;
105
106     if (p == NULL || *p == '\0')
107         return 0;
108
109     f = q = malloc(strlen(p) + 1);
110     strcpy(q, p);
111
112     r[c++] = "lhama";
113     for (;;) {
114         r[c++] = q;
115         while (*q != ' ' && *q != '\0')
116             q++;
117         if (*q == '\0')
118             break;
119         *q++ = '\0';
120     }
121     r[c] = NULL;
122
123     ret = parse_args(gfp, c, r, inPath, outPath, NULL, NULL);
124     free(f);
125     return ret;
126 }
127
128
129
130
131
132 static FILE *
133 init_files(lame_global_flags * gf, char const *inPath, char const *outPath)
134 {
135     FILE   *outf;
136     /* Mostly it is not useful to use the same input and output name.
137        This test is very easy and buggy and don't recognize different names
138        assigning the same file
139      */
140     if (0 != strcmp("-", outPath) && 0 == strcmp(inPath, outPath)) {
141         error_printf("Input file and Output file are the same. Abort.\n");
142         return NULL;
143     }
144
145     /* open the wav/aiff/raw pcm or mp3 input file.  This call will
146      * open the file, try to parse the headers and
147      * set gf.samplerate, gf.num_channels, gf.num_samples.
148      * if you want to do your own file input, skip this call and set
149      * samplerate, num_channels and num_samples yourself.
150      */
151     if (init_infile(gf, inPath) < 0) {
152         error_printf("Can't init infile '%s'\n", inPath);
153         return NULL;
154     }
155     if ((outf = init_outfile(outPath, lame_get_decode_only(gf))) == NULL) {
156         error_printf("Can't init outfile '%s'\n", outPath);
157         return NULL;
158     }
159
160     return outf;
161 }
162
163
164 static void
165 printInputFormat(lame_t gfp)
166 {
167     int const v_main = 2 - lame_get_version(gfp);
168     char const *v_ex = lame_get_out_samplerate(gfp) < 16000 ? ".5" : "";
169     switch (global_reader.input_format) {
170     case sf_mp123:     /* FIXME: !!! */
171         break;
172     case sf_mp3:
173         console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "III");
174         break;
175     case sf_mp2:
176         console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "II");
177         break;
178     case sf_mp1:
179         console_printf("MPEG-%u%s Layer %s", v_main, v_ex, "I");
180         break;
181     case sf_raw:
182         console_printf("raw PCM data");
183         break;
184     case sf_wave:
185         console_printf("Microsoft WAVE");
186         break;
187     case sf_aiff:
188         console_printf("SGI/Apple AIFF");
189         break;
190     default:
191         console_printf("unknown");
192         break;
193     }
194 }
195
196 /* the simple lame decoder */
197 /* After calling lame_init(), lame_init_params() and
198  * init_infile(), call this routine to read the input MP3 file
199  * and output .wav data to the specified file pointer*/
200 /* lame_decoder will ignore the first 528 samples, since these samples
201  * represent the mpglib delay (and are all 0).  skip = number of additional
202  * samples to skip, to (for example) compensate for the encoder delay */
203
204 static int
205 lame_decoder(lame_t gfp, FILE * outf, char *inPath, char *outPath)
206 {
207     short int Buffer[2][1152];
208     int     i, iread;
209     double  wavsize;
210     int     tmp_num_channels = lame_get_num_channels(gfp);
211     int     skip_start = samples_to_skip_at_start();
212     int     skip_end = samples_to_skip_at_end();
213     DecoderProgress dp = 0;
214
215     if (!(tmp_num_channels >= 1 && tmp_num_channels <= 2)) {
216         error_printf("Internal error.  Aborting.");
217         exit(-1);
218     }
219
220     if (global_ui_config.silent < 9) {
221         console_printf("\rinput:  %s%s(%g kHz, %i channel%s, ",
222                        strcmp(inPath, "-") ? inPath : "<stdin>",
223                        strlen(inPath) > 26 ? "\n\t" : "  ",
224                        lame_get_in_samplerate(gfp) / 1.e3,
225                        tmp_num_channels, tmp_num_channels != 1 ? "s" : "");
226
227         printInputFormat(gfp);
228
229         console_printf(")\noutput: %s%s(16 bit, Microsoft WAVE)\n",
230                        strcmp(outPath, "-") ? outPath : "<stdout>",
231                        strlen(outPath) > 45 ? "\n\t" : "  ");
232
233         if (skip_start > 0)
234             console_printf("skipping initial %i samples (encoder+decoder delay)\n", skip_start);
235         if (skip_end > 0)
236             console_printf("skipping final %i samples (encoder padding-decoder delay)\n", skip_end);
237
238         switch (global_reader.input_format) {
239         case sf_mp3:
240         case sf_mp2:
241         case sf_mp1:
242             dp = decoder_progress_init(lame_get_num_samples(gfp),
243                                        global_decoder.mp3input_data.framesize);
244             break;
245         case sf_raw:
246         case sf_wave:
247         case sf_aiff:
248         default:
249             dp = decoder_progress_init(lame_get_num_samples(gfp),
250                                        lame_get_in_samplerate(gfp) < 32000 ? 576 : 1152);
251             break;
252         }
253     }
254
255     if (0 == global_decoder.disable_wav_header)
256         WriteWaveHeader(outf, 0x7FFFFFFF, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
257     /* unknown size, so write maximum 32 bit signed value */
258
259     wavsize = 0;
260     do {
261         iread = get_audio16(gfp, Buffer); /* read in 'iread' samples */
262         if (iread >= 0) {
263             wavsize += iread;
264             if (dp != 0) {
265                 decoder_progress(dp, &global_decoder.mp3input_data, iread);
266             }
267             put_audio16(outf, Buffer, iread, tmp_num_channels);
268         }
269     } while (iread > 0);
270
271     i = (16 / 8) * tmp_num_channels;
272     assert(i > 0);
273     if (wavsize <= 0) {
274         if (global_ui_config.silent < 10)
275             error_printf("WAVE file contains 0 PCM samples\n");
276         wavsize = 0;
277     }
278     else if (wavsize > 0xFFFFFFD0 / i) {
279         if (global_ui_config.silent < 10)
280             error_printf("Very huge WAVE file, can't set filesize accordingly\n");
281         wavsize = 0xFFFFFFD0;
282     }
283     else {
284         wavsize *= i;
285     }
286     /* if outf is seekable, rewind and adjust length */
287     if (!global_decoder.disable_wav_header && strcmp("-", outPath)
288         && !fseek(outf, 0l, SEEK_SET))
289         WriteWaveHeader(outf, (int) wavsize, lame_get_in_samplerate(gfp), tmp_num_channels, 16);
290     fclose(outf);
291     close_infile();
292
293     if (dp != 0)
294         decoder_progress_finish(dp);
295     return 0;
296 }
297
298
299
300 static void
301 print_trailing_info(lame_global_flags * gf)
302 {
303     if (lame_get_findReplayGain(gf)) {
304         int     RadioGain = lame_get_RadioGain(gf);
305         console_printf("ReplayGain: %s%.1fdB\n", RadioGain > 0 ? "+" : "",
306                        ((float) RadioGain) / 10.0);
307         if (RadioGain > 0x1FE || RadioGain < -0x1FE)
308             error_printf
309                 ("WARNING: ReplayGain exceeds the -51dB to +51dB range. Such a result is too\n"
310                  "         high to be stored in the header.\n");
311     }
312
313     /* if (the user requested printing info about clipping) and (decoding
314        on the fly has actually been performed) */
315     if (global_ui_config.print_clipping_info && lame_get_decode_on_the_fly(gf)) {
316         float   noclipGainChange = (float) lame_get_noclipGainChange(gf) / 10.0f;
317         float   noclipScale = lame_get_noclipScale(gf);
318
319         if (noclipGainChange > 0.0) { /* clipping occurs */
320             console_printf
321                 ("WARNING: clipping occurs at the current gain. Set your decoder to decrease\n"
322                  "         the  gain  by  at least %.1fdB or encode again ", noclipGainChange);
323
324             /* advice the user on the scale factor */
325             if (noclipScale > 0) {
326                 console_printf("using  --scale %.2f\n", noclipScale);
327                 console_printf("         or less (the value under --scale is approximate).\n");
328             }
329             else {
330                 /* the user specified his own scale factor. We could suggest
331                  * the scale factor of (32767.0/gfp->PeakSample)*(gfp->scale)
332                  * but it's usually very inaccurate. So we'd rather advice him to
333                  * disable scaling first and see our suggestion on the scale factor then. */
334                 console_printf("using --scale <arg>\n"
335                                "         (For   a   suggestion  on  the  optimal  value  of  <arg>  encode\n"
336                                "         with  --scale 1  first)\n");
337             }
338
339         }
340         else {          /* no clipping */
341             if (noclipGainChange > -0.1)
342                 console_printf
343                     ("\nThe waveform does not clip and is less than 0.1dB away from full scale.\n");
344             else
345                 console_printf
346                     ("\nThe waveform does not clip and is at least %.1fdB away from full scale.\n",
347                      -noclipGainChange);
348         }
349     }
350
351 }
352
353
354 static int
355 write_xing_frame(lame_global_flags * gf, FILE * outf, size_t offset)
356 {
357     unsigned char mp3buffer[LAME_MAXMP3BUFFER];
358     size_t  imp3, owrite;
359
360     imp3 = lame_get_lametag_frame(gf, mp3buffer, sizeof(mp3buffer));
361     if (imp3 == 0) {
362         return 0;       /* nothing to do */
363     }
364     if (global_ui_config.silent <= 0) {
365         console_printf("Writing LAME Tag...");
366     }
367     if (imp3 > sizeof(mp3buffer)) {
368         error_printf
369             ("Error writing LAME-tag frame: buffer too small: buffer size=%d  frame size=%d\n",
370              sizeof(mp3buffer), imp3);
371         return -1;
372     }
373     if (fseek(outf, offset, SEEK_SET) != 0) {
374         error_printf("fatal error: can't update LAME-tag frame!\n");
375         return -1;
376     }
377     owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
378     if (owrite != imp3) {
379         error_printf("Error writing LAME-tag \n");
380         return -1;
381     }
382     if (global_ui_config.silent <= 0) {
383         console_printf("done\n");
384     }
385     return imp3;
386 }
387
388
389 static int
390 write_id3v1_tag(lame_t gf, FILE * outf)
391 {
392     unsigned char mp3buffer[128];
393     int     imp3, owrite;
394
395     imp3 = lame_get_id3v1_tag(gf, mp3buffer, sizeof(mp3buffer));
396     if (imp3 <= 0) {
397         return 0;
398     }
399     if ((size_t) imp3 > sizeof(mp3buffer)) {
400         error_printf("Error writing ID3v1 tag: buffer too small: buffer size=%d  ID3v1 size=%d\n",
401                      sizeof(mp3buffer), imp3);
402         return 0;       /* not critical */
403     }
404     owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
405     if (owrite != imp3) {
406         error_printf("Error writing ID3v1 tag \n");
407         return 1;
408     }
409     return 0;
410 }
411
412
413 static int
414 lame_encoder_loop(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
415 {
416     unsigned char mp3buffer[LAME_MAXMP3BUFFER];
417     int     Buffer[2][1152];
418     int     iread, imp3, owrite;
419     size_t  id3v2_size;
420
421     encoder_progress_begin(gf, inPath, outPath);
422
423     id3v2_size = lame_get_id3v2_tag(gf, 0, 0);
424     if (id3v2_size > 0) {
425         unsigned char *id3v2tag = malloc(id3v2_size);
426         if (id3v2tag != 0) {
427             imp3 = lame_get_id3v2_tag(gf, id3v2tag, id3v2_size);
428             owrite = (int) fwrite(id3v2tag, 1, imp3, outf);
429             free(id3v2tag);
430             if (owrite != imp3) {
431                 encoder_progress_end(gf);
432                 error_printf("Error writing ID3v2 tag \n");
433                 return 1;
434             }
435         }
436     }
437     else {
438         unsigned char* id3v2tag = getOldTag(gf);
439         id3v2_size = sizeOfOldTag(gf);
440         if ( id3v2_size > 0 ) {
441             size_t owrite = fwrite(id3v2tag, 1, id3v2_size, outf);
442             if (owrite != id3v2_size) {
443                 encoder_progress_end(gf);
444                 error_printf("Error writing ID3v2 tag \n");
445                 return 1;
446             }
447         }
448     }
449     if (global_writer.flush_write == 1) {
450         fflush(outf);
451     }
452
453     /* encode until we hit eof */
454     do {
455         /* read in 'iread' samples */
456         iread = get_audio(gf, Buffer);
457
458         if (iread >= 0) {
459             encoder_progress(gf);
460
461             /* encode */
462             imp3 = 0;
463             imp3 = lame_encode_buffer_int(gf, Buffer[0], Buffer[1], iread,
464                 mp3buffer, sizeof(mp3buffer));
465
466             /* was our output buffer big enough? */
467             if (imp3 < 0) {
468                 if (imp3 == -1)
469                     error_printf("mp3 buffer is not big enough... \n");
470                 else
471                     error_printf("mp3 internal error:  error code=%i\n", imp3);
472                 return 1;
473             }
474             owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
475             if (owrite != imp3) {
476                 error_printf("Error writing mp3 output \n");
477                 return 1;
478             }
479         }
480         if (global_writer.flush_write == 1) {
481             fflush(outf);
482         }
483     } while (iread > 0);
484
485     if (nogap)
486         imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
487     else
488         imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */
489
490     if (imp3 < 0) {
491         if (imp3 == -1)
492             error_printf("mp3 buffer is not big enough... \n");
493         else
494             error_printf("mp3 internal error:  error code=%i\n", imp3);
495         return 1;
496
497     }
498
499     encoder_progress_end(gf);
500
501     owrite = (int) fwrite(mp3buffer, 1, imp3, outf);
502     if (owrite != imp3) {
503         error_printf("Error writing mp3 output \n");
504         return 1;
505     }
506     if (global_writer.flush_write == 1) {
507         fflush(outf);
508     }
509     imp3 = write_id3v1_tag(gf, outf);
510     if (global_writer.flush_write == 1) {
511         fflush(outf);
512     }
513     if (imp3) {
514         return 1;
515     }
516     write_xing_frame(gf, outf, id3v2_size);
517     if (global_writer.flush_write == 1) {
518         fflush(outf);
519     }
520     if (global_ui_config.silent <= 0) {
521         print_trailing_info(gf);
522     }
523     return 0;
524 }
525
526
527 static int
528 lame_encoder(lame_global_flags * gf, FILE * outf, int nogap, char *inPath, char *outPath)
529 {
530     int     ret;
531
532     ret = lame_encoder_loop(gf, outf, nogap, inPath, outPath);
533     fclose(outf);       /* close the output file */
534     close_infile();     /* close the input file */
535     return ret;
536 }
537
538
539 static void
540 parse_nogap_filenames(int nogapout, char const *inPath, char *outPath, char *outdir)
541 {
542     char const *slasher;
543     size_t  n;
544
545     /* FIXME: replace strcpy by safer strncpy */
546     strcpy(outPath, outdir);
547     if (!nogapout) {
548         strncpy(outPath, inPath, PATH_MAX + 1 - 4);
549         n = strlen(outPath);
550         /* nuke old extension, if one  */
551         if (outPath[n - 3] == 'w'
552             && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
553             outPath[n - 3] = 'm';
554             outPath[n - 2] = 'p';
555             outPath[n - 1] = '3';
556         }
557         else {
558             outPath[n + 0] = '.';
559             outPath[n + 1] = 'm';
560             outPath[n + 2] = 'p';
561             outPath[n + 3] = '3';
562             outPath[n + 4] = 0;
563         }
564     }
565     else {
566         slasher = inPath;
567         slasher += PATH_MAX + 1 - 4;
568
569         /* backseek to last dir delemiter */
570         while (*slasher != '/' && *slasher != '\\' && slasher != inPath && *slasher != ':') {
571             slasher--;
572         }
573
574         /* skip one foward if needed */
575         if (slasher != inPath
576             && (outPath[strlen(outPath) - 1] == '/'
577                 || outPath[strlen(outPath) - 1] == '\\' || outPath[strlen(outPath) - 1] == ':'))
578             slasher++;
579         else if (slasher == inPath
580                  && (outPath[strlen(outPath) - 1] != '/'
581                      &&
582                      outPath[strlen(outPath) - 1] != '\\' && outPath[strlen(outPath) - 1] != ':'))
583             /* FIXME: replace strcat by safer strncat */
584 #ifdef _WIN32
585             strncat(outPath, "\\", PATH_MAX + 1 - 4);
586 #elif __OS2__
587             strncat(outPath, "\\", PATH_MAX + 1 - 4);
588 #else
589             strncat(outPath, "/", PATH_MAX + 1 - 4);
590 #endif
591
592         strncat(outPath, slasher, PATH_MAX + 1 - 4);
593         n = strlen(outPath);
594         /* nuke old extension  */
595         if (outPath[n - 3] == 'w'
596             && outPath[n - 2] == 'a' && outPath[n - 1] == 'v' && outPath[n - 4] == '.') {
597             outPath[n - 3] = 'm';
598             outPath[n - 2] = 'p';
599             outPath[n - 1] = '3';
600         }
601         else {
602             outPath[n + 0] = '.';
603             outPath[n + 1] = 'm';
604             outPath[n + 2] = 'p';
605             outPath[n + 3] = '3';
606             outPath[n + 4] = 0;
607         }
608     }
609 }
610
611
612 int
613 lame_main(lame_t gf, int argc, char **argv)
614 {
615     char    inPath[PATH_MAX + 1];
616     char    outPath[PATH_MAX + 1];
617     char    nogapdir[PATH_MAX + 1];
618     /* support for "nogap" encoding of up to 200 .wav files */
619 #define MAX_NOGAP 200
620     int     nogapout = 0;
621     int     max_nogap = MAX_NOGAP;
622     char    nogap_inPath_[MAX_NOGAP][PATH_MAX + 1];
623     char   *nogap_inPath[MAX_NOGAP];
624
625     int     ret;
626     int     i;
627     FILE   *outf;
628
629     lame_set_msgf(gf, &frontend_msgf);
630     lame_set_errorf(gf, &frontend_errorf);
631     lame_set_debugf(gf, &frontend_debugf);
632     if (argc <= 1) {
633         usage(stderr, argv[0]); /* no command-line args, print usage, exit  */
634         return 1;
635     }
636
637     memset(inPath, 0, sizeof(inPath));
638     memset(nogap_inPath_, 0, sizeof(nogap_inPath_));
639     for (i = 0; i < MAX_NOGAP; ++i) {
640         nogap_inPath[i] = &nogap_inPath_[i][0];
641     }
642
643     /* parse the command line arguments, setting various flags in the
644      * struct 'gf'.  If you want to parse your own arguments,
645      * or call libmp3lame from a program which uses a GUI to set arguments,
646      * skip this call and set the values of interest in the gf struct.
647      * (see the file API and lame.h for documentation about these parameters)
648      */
649     {
650         char   *str = lame_getenv("LAMEOPT");
651         parse_args_from_string(gf, str, inPath, outPath);
652         free(str);
653     }
654     ret = parse_args(gf, argc, argv, inPath, outPath, nogap_inPath, &max_nogap);
655     if (ret < 0) {
656         return ret == -2 ? 0 : 1;
657     }
658     if (global_ui_config.update_interval < 0.)
659         global_ui_config.update_interval = 2.;
660
661     if (outPath[0] != '\0' && max_nogap > 0) {
662         strncpy(nogapdir, outPath, PATH_MAX + 1);
663         nogapout = 1;
664     }
665
666     /* initialize input file.  This also sets samplerate and as much
667        other data on the input file as available in the headers */
668     if (max_nogap > 0) {
669         /* for nogap encoding of multiple input files, it is not possible to
670          * specify the output file name, only an optional output directory. */
671         parse_nogap_filenames(nogapout, nogap_inPath[0], outPath, nogapdir);
672         outf = init_files(gf, nogap_inPath[0], outPath);
673     }
674     else {
675         outf = init_files(gf, inPath, outPath);
676     }
677     if (outf == NULL) {
678         return -1;
679     }
680     /* turn off automatic writing of ID3 tag data into mp3 stream 
681      * we have to call it before 'lame_init_params', because that
682      * function would spit out ID3v2 tag data.
683      */
684     lame_set_write_id3tag_automatic(gf, 0);
685
686     /* Now that all the options are set, lame needs to analyze them and
687      * set some more internal options and check for problems
688      */
689     ret = lame_init_params(gf);
690     if (ret < 0) {
691         if (ret == -1) {
692             display_bitrates(stderr);
693         }
694         error_printf("fatal error during initialization\n");
695         return ret;
696     }
697
698     if (global_ui_config.silent > 0) {
699         global_ui_config.brhist = 0; /* turn off VBR histogram */
700     }
701
702     if (lame_get_decode_only(gf)) {
703         /* decode an mp3 file to a .wav */
704         ret = lame_decoder(gf, outf, inPath, outPath);
705     }
706     else if (max_nogap == 0) {
707         /* encode a single input file */
708         ret = lame_encoder(gf, outf, 0, inPath, outPath);
709     }
710     else {
711         /* encode multiple input files using nogap option */
712         for (i = 0; i < max_nogap; ++i) {
713             int     use_flush_nogap = (i != (max_nogap - 1));
714             if (i > 0) {
715                 parse_nogap_filenames(nogapout, nogap_inPath[i], outPath, nogapdir);
716                 /* note: if init_files changes anything, like
717                    samplerate, num_channels, etc, we are screwed */
718                 outf = init_files(gf, nogap_inPath[i], outPath);
719                 /* reinitialize bitstream for next encoding.  this is normally done
720                  * by lame_init_params(), but we cannot call that routine twice */
721                 lame_init_bitstream(gf);
722             }
723             lame_set_nogap_total(gf, max_nogap);
724             lame_set_nogap_currentindex(gf, i);
725             ret = lame_encoder(gf, outf, use_flush_nogap, nogap_inPath[i], outPath);
726         }
727     }
728     return ret;
729 }