1 /* SoX - The Swiss Army Knife of Audio Manipulation.
2  *
3  * This is the main function for the SoX command line programs:
4  *   sox, play, rec, soxi.
5  *
6  * Copyright 1998-2009 Chris Bagwell and SoX contributors
7  * Copyright 1991 Lance Norskog And Sundry Contributors
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
17  * Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #include "soxconfig.h"
25 #include "sox.h"
26 #include "util.h"
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <math.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <time.h>
39 
40 #if defined(HAVE_WIN32_GLOB_H)
41   #include "win32-glob.h"
42   #define HAVE_GLOB_H 1
43 #elif defined(HAVE_GLOB_H)
44   #include <glob.h>
45 #endif
46 
47 #ifdef HAVE_IO_H
48   #include <io.h>
49 #endif
50 
51 #ifdef HAVE_SUN_AUDIOIO_H
52   #include <sun/audioio.h>
53   #define HAVE_AUDIOIO_H 1
54 #else
55 #ifdef HAVE_SYS_AUDIOIO_H
56   #include <sys/audioio.h>
57   #define HAVE_AUDIOIO_H 1
58 #endif
59 #endif
60 
61 #ifdef HAVE_SYS_SOUNDCARD_H
62   #include <sys/soundcard.h>
63   #define HAVE_SOUNDCARD_H 1
64 #else
65 #ifdef HAVE_MACHINE_SOUNDCARD_H
66   #include <machine/soundcard.h>
67   #define HAVE_SOUNDCARD_H 1
68 #endif
69 #endif
70 
71 #ifdef HAVE_SYS_TIME_H
72   #include <sys/time.h>
73 #endif
74 
75 #ifdef HAVE_SYS_TIMEB_H
76   #include <sys/timeb.h>
77 #endif
78 
79 #ifdef HAVE_SYS_UTSNAME_H
80   #include <sys/utsname.h>
81 #endif
82 
83 #ifdef HAVE_UNISTD_H
84   #include <unistd.h>
85 #endif
86 
87 #ifdef HAVE_GETTIMEOFDAY
88   #define TIME_FRAC 1e6
89 #else
90   #define timeval timeb
91   #define gettimeofday(a,b) ftime(a)
92   #define tv_sec time
93   #define tv_usec millitm
94   #define TIME_FRAC 1e3
95 #endif
96 
97 #if !defined(HAVE_CONIO_H) && !defined(HAVE_TERMIOS_H) && (defined(_MSC_VER) || defined(__MINGW32__))
98 #define HAVE_CONIO_H 1
99 #endif
100 
101 #ifdef HAVE_CONIO_H
102 /* _kbhit and _getch */
103 #include <conio.h>
104 #undef HAVE_TERMIOS_H
105 #endif
106 
107 /*#define MORE_INTERACTIVE 1*/
108 
109 #define SOX_OPTS "SOX_OPTS"
110 static lsx_getopt_t optstate;
111 
112 /* argv[0] options */
113 
114 static char const * myname = NULL;
115 static enum {sox_sox, sox_play, sox_rec, sox_soxi} sox_mode;
116 
117 
118 /* gopts */
119 
120 static enum {
121   sox_sequence, sox_concatenate, sox_mix, sox_mix_power,
122   sox_merge, sox_multiply, sox_default
123 } combine_method = sox_default;
124 static enum { sox_single, sox_multiple } output_method = sox_single;
125 #define is_serial(m) ((m) <= sox_concatenate)
126 #define is_parallel(m) (!is_serial(m))
127 static sox_bool no_clobber = sox_false, interactive = sox_false;
128 static sox_bool uservolume = sox_false;
129 typedef enum {RG_off, RG_track, RG_album, RG_default} rg_mode;
130 static lsx_enum_item const rg_modes[] = {
131   LSX_ENUM_ITEM(RG_,off)
132   LSX_ENUM_ITEM(RG_,track)
133   LSX_ENUM_ITEM(RG_,album)
134   {0, 0}};
135 static rg_mode replay_gain_mode = RG_default;
136 static sox_option_t show_progress = sox_option_default;
137 
138 
139 /* Input & output files */
140 
141 typedef struct {
142   char * filename;
143 
144   /* fopts */
145   char const * filetype;
146   sox_signalinfo_t signal;
147   sox_encodinginfo_t encoding;
148   double volume;
149   double replay_gain;
150   sox_oob_t oob;
151   sox_bool no_glob;
152 
153   sox_format_t * ft;  /* libSoX file descriptor */
154   uint64_t volume_clips;
155   rg_mode replay_gain_mode;
156 } file_t;
157 
158 static file_t * * files = NULL; /* Array tracking input and output files */
159 #define ofile files[file_count - 1]
160 static size_t file_count = 0;
161 static size_t input_count = 0;
162 static size_t output_count = 0;
163 
164 /* Effects */
165 
166 /* We parse effects into a temporary effects table and then place into
167  * the real effects chain.  This allows scanning all effects to give
168  * hints to what input effect options should be as well as determining
169  * when mixer or resample effects need to be auto-inserted as well.
170  */
171 static sox_effect_t **user_efftab = NULL;
172 static size_t user_efftab_size = 0;
173 static sox_effects_chain_t *effects_chain = NULL;
174 static sox_effect_t *save_output_eff = NULL;
175 
176 static struct { char *name; int argc; char **argv; size_t argv_size; } **user_effargs = NULL;
177 static size_t *user_effargs_size = NULL;  /* array: size of user_effargs for each chain */
178 /* Size of memory structures related to effects arguments (user_effargs[i],
179  * user_effargs[i][j].argv) to be extended in steps of EFFARGS_STEP */
180 #define EFFARGS_STEP 8
181 static size_t *nuser_effects = NULL;  /* array: number of effects in each chain */
182 static size_t current_eff_chain = 0;
183 static size_t eff_chain_count = 0;
184 static sox_bool very_first_effchain = sox_true;
185   /* Indicates that not only the first effects chain is in effect (hrm), but
186      also that it has never been restarted. Only then we may use the
187      optimize_trim() hack. */
188 static char *effects_filename = NULL;
189 static char * play_rate_arg = NULL;
190 static char *norm_level = NULL;
191 
192 /* Flowing */
193 
194 static sox_signalinfo_t combiner_signal, ofile_signal_options;
195 static sox_encodinginfo_t combiner_encoding, ofile_encoding_options;
196 static uint64_t mixing_clips = 0;
197 static size_t current_input = 0;
198 static uint64_t input_wide_samples = 0;
199 static uint64_t read_wide_samples = 0;
200 static uint64_t output_samples = 0;
201 static sox_bool input_eof = sox_false;
202 static sox_bool output_eof = sox_false;
203 static sox_bool user_abort = sox_false;
204 static sox_bool user_skip = sox_false;
205 static sox_bool user_restart_eff = sox_false;
206 static int success = 0;
207 static int cleanup_called = 0;
208 static sox_sample_t omax[2], omin[2];
209 
210 #ifdef HAVE_TERMIOS_H
211 #include <termios.h>
212 static struct termios original_termios;
213 static sox_bool original_termios_saved = sox_false;
214 #endif
215 
216 static sox_bool stdin_is_a_tty, is_player, is_guarded, do_guarded_norm, no_dither, reported_sox_opts;
217 
218 struct timeval load_timeofday;
219 
220 static void cleanup(void)
221 {
222   size_t i;
223 
224   if (!success && !reported_sox_opts) {
225     char const * env_opts = getenv(SOX_OPTS);
226     if (env_opts && *env_opts)
227       lsx_report("used "SOX_OPTS"=%s", env_opts);
228   }
229   /* Close the input and output files before exiting. */
230   for (i = 0; i < input_count; i++) {
231     if (files[i]->ft) {
232       sox_close(files[i]->ft);
233     }
234     free(files[i]->filename);
235     free(files[i]);
236   }
237 
238   if (file_count) {
239     if (ofile->ft) {
240       if (!success && ofile->ft->io_type == lsx_io_file) {   /* If we failed part way through */
241         struct stat st;                  /* writing a normal file, remove it. */
242         if (!stat(ofile->ft->filename, &st) &&
243             (st.st_mode & S_IFMT) == S_IFREG)
244           unlink(ofile->ft->filename);
245       }
246       sox_close(ofile->ft); /* Assume we can unlink a file before closing it. */
247     }
248     free(ofile->filename);
249     free(ofile);
250   }
251 
252   free(files);
253 
254 #ifdef HAVE_TERMIOS_H
255   if (original_termios_saved)
256     tcsetattr(fileno(stdin), TCSANOW, &original_termios);
257 #endif
258 
259   free(user_efftab);
260 
261   free(sox_globals.tmp_path);
262   sox_globals.tmp_path = NULL;
263 
264   free(play_rate_arg);
265   free(effects_filename);
266   free(norm_level);
267 
268   sox_quit();
269 
270   cleanup_called = 1;
271 }
272 
273 /* Cleanup atexit() function, hence always called. */
274 static void atexit_cleanup(void)
275 {
276   /* Do not call cleanup using atexit() if possible.  pthread's can
277    * act unpredictable if called outside of main().
278    */
279   if (!cleanup_called)
280     cleanup();
281 }
282 
283 static char const * str_time(double seconds)
284 {
285   static char string[16][50];
286   static int i;
287   int hours, mins = seconds / 60;
288   seconds -= mins * 60;
289   hours = mins / 60;
290   mins -= hours * 60;
291   i = (i+1) & 15;
292   sprintf(string[i], "%02i:%02i:%05.2f", hours, mins, seconds);
293   return string[i];
294 }
295 
296 static char const * size_and_bitrate(sox_format_t * ft, char const * * text)
297 {
298   off_t size = lsx_filelength(ft);
299   if (ft->signal.length && ft->signal.channels && ft->signal.rate && text) {
300     double secs = ft->signal.length / ft->signal.channels / ft->signal.rate;
301     *text = lsx_sigfigs3(8. * size / secs);
302   }
303   return lsx_sigfigs3((double)size);
304 }
305 
306 static void play_file_info(sox_format_t * ft, file_t * f, sox_bool full)
307 {
308   FILE * const output = sox_mode == sox_soxi? stdout : stderr;
309   char const * text, * text2 = NULL;
310   char buffer[30];
311   uint64_t ws = ft->signal.length / ft->signal.channels;
312   (void)full;
313 
314   fprintf(output, "\n");
315   if (ft->filename[0]) {
316     fprintf(output, "%s:", ft->filename);
317     if (strcmp(ft->filename, "-") == 0 || (ft->handler.flags & SOX_FILE_DEVICE))
318       fprintf(output, " (%s)", ft->handler.names[0]);
319     fprintf(output, "\n\n");
320   }
321 
322   if ((text = size_and_bitrate(ft, &text2))) {
323     fprintf(output, " File Size: %-10s", text);
324     if (text2)
325       fprintf(output, "Bit Rate: %s", text2);
326     fprintf(output, "\n");
327   }
328 
329   fprintf(output, "  Encoding: %-14s", sox_encodings_info[ft->encoding.encoding].name);
330   text = sox_find_comment(f->ft->oob.comments, "Comment");
331   if (!text)
332     text = sox_find_comment(f->ft->oob.comments, "Description");
333   if (!text)
334     text = sox_find_comment(f->ft->oob.comments, "Year");
335   if (text)
336     fprintf(output, "Info: %s", text);
337   fprintf(output, "\n");
338 
339   sprintf(buffer, "  Channels: %u @ %u-bit", ft->signal.channels, ft->signal.precision);
340   fprintf(output, "%-25s", buffer);
341   text = sox_find_comment(f->ft->oob.comments, "Tracknumber");
342   if (text) {
343     fprintf(output, "Track: %s", text);
344     text = sox_find_comment(f->ft->oob.comments, "Tracktotal");
345     if (text)
346       fprintf(output, " of %s", text);
347   }
348   fprintf(output, "\n");
349 
350   sprintf(buffer, "Samplerate: %gHz", ft->signal.rate);
351   fprintf(output, "%-25s", buffer);
352   text = sox_find_comment(f->ft->oob.comments, "Album");
353   if (text)
354     fprintf(output, "Album: %s", text);
355   fprintf(output, "\n");
356 
357   if (f && f->replay_gain != HUGE_VAL){
358     sprintf(buffer, "%s gain: %+.1fdB", lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text, f->replay_gain);
359     buffer[0] += 'A' - 'a';
360     fprintf(output, "%-24s", buffer);
361   } else
362     fprintf(output, "%-24s", "Replaygain: off");
363   text = sox_find_comment(f->ft->oob.comments, "Artist");
364   if (text)
365     fprintf(output, "Artist: %s", text);
366   fprintf(output, "\n");
367 
368   fprintf(output, "  Duration: %-13s", ft->signal.length? str_time((double)ws / ft->signal.rate) : "unknown");
369   text = sox_find_comment(f->ft->oob.comments, "Title");
370   if (text)
371     fprintf(output, "Title: %s", text);
372   fprintf(output, "\n\n");
373 }
374 
375 static void display_file_info(sox_format_t * ft, file_t * f, sox_bool full)
376 {
377   static char const * const no_yes[] = {"no", "yes"};
378   FILE * const output = sox_mode == sox_soxi? stdout : stderr;
379   char const * filetype = lsx_find_file_extension(ft->filename);
380   sox_bool show_type = sox_true;
381   size_t i;
382 
383   if (is_player && sox_globals.verbosity < 3) {
384     play_file_info(ft, f, full);
385     return;
386   }
387 
388   fprintf(output, "\n%s: '%s'",
389     ft->mode == 'r'? "Input File     " : "Output File    ", ft->filename);
390   if (filetype) for (i = 0; ft->handler.names[i] && show_type; ++i)
391     if (!strcasecmp(filetype, ft->handler.names[i]))
392       show_type = sox_false;
393   if (show_type)
394     fprintf(output, " (%s)", ft->handler.names[0]);
395   fprintf(output, "\n");
396 
397   fprintf(output,
398     "Channels       : %u\n"
399     "Sample Rate    : %g\n"
400     "Precision      : %u-bit\n",
401     ft->signal.channels,
402     ft->signal.rate,
403     ft->signal.precision);
404 
405   if (ft->signal.length && ft->signal.channels && ft->signal.rate) {
406     uint64_t ws = ft->signal.length / ft->signal.channels;
407     char const * text, * text2 = NULL;
408     fprintf(output,
409         "Duration       : %s = %" PRIu64 " samples %c %g CDDA sectors\n",
410         str_time((double)ws / ft->signal.rate),
411         ws, "~="[ft->signal.rate == 44100],
412         (double)ws / ft->signal.rate * 44100 / 588);
413     if (ft->mode == 'r' && (text = size_and_bitrate(ft, &text2))) {
414       fprintf(output, "File Size      : %s\n", text);
415       if (text2)
416         fprintf(output, "Bit Rate       : %s\n", text2);
417     }
418   }
419 
420   if (ft->encoding.encoding) {
421     char buffer[20] = {'\0'};
422     if (ft->encoding.bits_per_sample)
423       sprintf(buffer, "%u-bit ", ft->encoding.bits_per_sample);
424 
425     fprintf(output, "Sample Encoding: %s%s\n", buffer,
426         sox_encodings_info[ft->encoding.encoding].desc);
427   }
428 
429   if (full) {
430     if (ft->encoding.bits_per_sample > 8 || (ft->handler.flags & SOX_FILE_ENDIAN))
431       fprintf(output, "Endian Type    : %s\n",
432           ft->encoding.reverse_bytes != MACHINE_IS_BIGENDIAN ? "big" : "little");
433     if (ft->encoding.bits_per_sample)
434       fprintf(output,
435         "Reverse Nibbles: %s\n"
436         "Reverse Bits   : %s\n",
437         no_yes[ft->encoding.reverse_nibbles],
438         no_yes[ft->encoding.reverse_bits]);
439   }
440 
441   if (f && f->replay_gain != HUGE_VAL)
442     fprintf(output, "Replay gain    : %+g dB (%s)\n" , f->replay_gain,
443         lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text);
444   if (f && f->volume != HUGE_VAL)
445     fprintf(output, "Level adjust   : %g (linear gain)\n" , f->volume);
446 
447   if (!(ft->handler.flags & SOX_FILE_DEVICE) && ft->oob.comments) {
448     if (sox_num_comments(ft->oob.comments) > 1) {
449       sox_comments_t p = ft->oob.comments;
450       fprintf(output, "Comments       : \n");
451       do fprintf(output, "%s\n", *p);
452       while (*++p);
453     }
454     else fprintf(output, "Comment        : '%s'\n", ft->oob.comments[0]);
455   }
456   fprintf(output, "\n");
457 }
458 
459 static void report_file_info(file_t * f)
460 {
461   if (sox_globals.verbosity > 2)
462     display_file_info(f->ft, f, sox_true);
463 }
464 
465 static void progress_to_next_input_file(file_t * f, sox_effect_t * effp)
466 {
467   if (user_skip) {
468     user_skip = sox_false;
469     fprintf(stderr, "\nSkipped (Ctrl-C twice to quit).\n");
470   }
471   read_wide_samples = 0;
472   input_wide_samples = f->ft->signal.length / f->ft->signal.channels;
473   if (show_progress && (sox_globals.verbosity < 3 ||
474                         (is_serial(combine_method) && input_count > 1)))
475     display_file_info(f->ft, f, sox_false);
476   if (f->volume == HUGE_VAL)
477     f->volume = 1;
478   if (f->replay_gain != HUGE_VAL)
479     f->volume *= pow(10.0, f->replay_gain / 20);
480   if (effp && f->volume != floor(f->volume))
481     effp->out_signal.precision = SOX_SAMPLE_PRECISION;
482   f->ft->sox_errno = errno = 0;
483 }
484 
485 /* Read up to max `wide' samples.  A wide sample contains one sample per channel
486  * from the input audio. */
487 static size_t sox_read_wide(sox_format_t * ft, sox_sample_t * buf, size_t max)
488 {
489   size_t len = max / combiner_signal.channels;
490   len = sox_read(ft, buf, len * ft->signal.channels) / ft->signal.channels;
491   if (!len && ft->sox_errno)
492     lsx_fail("`%s' %s: %s",
493         ft->filename, ft->sox_errstr, sox_strerror(ft->sox_errno));
494   return len;
495 }
496 
497 static void balance_input(sox_sample_t * buf, size_t ws, file_t * f)
498 {
499   size_t s = ws * f->ft->signal.channels;
500 
501   if (f->volume != 1) while (s--) {
502     double d = f->volume * *buf;
503     *buf++ = SOX_ROUND_CLIP_COUNT(d, f->volume_clips);
504   }
505 }
506 
507 /* The input combiner: contains one sample buffer per input file, but only
508  * needed if is_parallel(combine_method) */
509 typedef struct {
510   sox_sample_t * * ibuf;
511   size_t *         ilen;
512 } input_combiner_t;
513 
514 static int combiner_start(sox_effect_t *effp)
515 {
516   input_combiner_t * z = (input_combiner_t *) effp->priv;
517   uint64_t ws;
518   size_t i;
519 
520   if (is_serial(combine_method))
521     progress_to_next_input_file(files[current_input], effp);
522   else {
523     ws = 0;
524     z->ibuf = lsx_malloc(input_count * sizeof(*z->ibuf));
525     for (i = 0; i < input_count; i++) {
526       z->ibuf[i] = lsx_malloc(sox_globals.bufsiz * sizeof(sox_sample_t));
527       progress_to_next_input_file(files[i], effp);
528       ws = max(ws, input_wide_samples);
529     }
530     input_wide_samples = ws; /* Output length is that of longest input file. */
531   }
532   z->ilen = lsx_malloc(input_count * sizeof(*z->ilen));
533   return SOX_SUCCESS;
534 }
535 
536 static sox_bool can_segue(size_t i)
537 {
538   return
539     files[i]->ft->signal.channels == files[i - 1]->ft->signal.channels &&
540     files[i]->ft->signal.rate     == files[i - 1]->ft->signal.rate;
541 }
542 
543 static int combiner_drain(sox_effect_t *effp, sox_sample_t * obuf, size_t * osamp)
544 {
545   input_combiner_t * z = (input_combiner_t *) effp->priv;
546   size_t ws, s, i;
547   size_t olen = 0;
548 
549   if (is_serial(combine_method)) {
550     while (sox_true) {
551       if (!user_skip)
552         olen = sox_read_wide(files[current_input]->ft, obuf, *osamp);
553       if (olen == 0) {   /* If EOF, go to the next input file. */
554         if (++current_input < input_count) {
555           if (combine_method == sox_sequence && !can_segue(current_input))
556             break;
557           progress_to_next_input_file(files[current_input], NULL);
558           continue;
559         }
560       }
561       balance_input(obuf, olen, files[current_input]);
562       break;
563     } /* while */
564   } /* is_serial */ else { /* else is_parallel() */
565     sox_sample_t * p = obuf;
566     for (i = 0; i < input_count; ++i) {
567       z->ilen[i] = sox_read_wide(files[i]->ft, z->ibuf[i], *osamp);
568       balance_input(z->ibuf[i], z->ilen[i], files[i]);
569       olen = max(olen, z->ilen[i]);
570     }
571     for (ws = 0; ws < olen; ++ws) { /* wide samples */
572       if (combine_method == sox_mix || combine_method == sox_mix_power) {
573         for (s = 0; s < effp->in_signal.channels; ++s, ++p) { /* sum samples */
574           *p = 0;
575           for (i = 0; i < input_count; ++i)
576             if (ws < z->ilen[i] && s < files[i]->ft->signal.channels) {
577               /* Cast to double prevents integer overflow */
578               double sample = *p + (double)z->ibuf[i][ws * files[i]->ft->signal.channels + s];
579               *p = SOX_ROUND_CLIP_COUNT(sample, mixing_clips);
580             }
581         }
582       } /* sox_mix */ else if (combine_method == sox_multiply)  {
583         for (s = 0; s < effp->in_signal.channels; ++s, ++p) { /* multiply samples */
584           i = 0;
585           *p = ws < z->ilen[i] && s < files[i]->ft->signal.channels?
586             z->ibuf[i][ws * files[i]->ft->signal.channels + s] : 0;
587           for (++i; i < input_count; ++i) {
588             double sample = *p * (-1. / SOX_SAMPLE_MIN) * (ws < z->ilen[i] && s < files[i]->ft->signal.channels? z->ibuf[i][ws * files[i]->ft->signal.channels + s] : 0);
589             *p = SOX_ROUND_CLIP_COUNT(sample, mixing_clips);
590           }
591         }
592       } /* sox_multiply */ else { /* sox_merge: like a multi-track recorder */
593         for (i = 0; i < input_count; ++i)
594           for (s = 0; s < files[i]->ft->signal.channels; ++s)
595             *p++ = (ws < z->ilen[i]) * z->ibuf[i][ws * files[i]->ft->signal.channels + s];
596       } /* sox_merge */
597     } /* wide samples */
598   } /* is_parallel */
599   read_wide_samples += olen;
600   olen *= effp->in_signal.channels;
601   *osamp = olen;
602 
603   input_eof = olen ? sox_false : sox_true;
604 
605   if (input_eof && is_parallel(combine_method))
606     current_input += input_count;
607 
608   return olen? SOX_SUCCESS : SOX_EOF;
609 }
610 
611 static int combiner_stop(sox_effect_t *effp)
612 {
613   input_combiner_t * z = (input_combiner_t *) effp->priv;
614   size_t i;
615 
616   if (is_parallel(combine_method)) {
617     /* Free input buffers now that they are not used */
618     for (i = 0; i < input_count; i++)
619       free(z->ibuf[i]);
620     free(z->ibuf);
621   }
622   free(z->ilen);
623 
624   return SOX_SUCCESS;
625 }
626 
627 static sox_effect_handler_t const * input_combiner_effect_fn(void)
628 {
629   static sox_effect_handler_t handler = { "input", 0, SOX_EFF_MCHAN |
630     SOX_EFF_MODIFY, 0, combiner_start, 0, combiner_drain,
631     combiner_stop, 0, sizeof(input_combiner_t)
632   };
633   return &handler;
634 }
635 
636 static int ostart(sox_effect_t *effp)
637 {
638   unsigned prec = effp->out_signal.precision;
639   if (effp->in_signal.mult && effp->in_signal.precision > prec)
640     *effp->in_signal.mult *= 1 - (1 << (31 - prec)) * (1. / SOX_SAMPLE_MAX);
641   return SOX_SUCCESS;
642 }
643 
644 static int output_flow(sox_effect_t *effp, sox_sample_t const * ibuf,
645     sox_sample_t * obuf, size_t * isamp, size_t * osamp)
646 {
647   size_t len;
648 
649   (void)effp, (void)obuf;
650   if (show_progress) for (len = 0; len < *isamp; len += effp->in_signal.channels) {
651     omax[0] = max(omax[0], ibuf[len]);
652     omin[0] = min(omin[0], ibuf[len]);
653     if (effp->in_signal.channels > 1) {
654       omax[1] = max(omax[1], ibuf[len + 1]);
655       omin[1] = min(omin[1], ibuf[len + 1]);
656     }
657     else {
658       omax[1] = omax[0];
659       omin[1] = omin[0];
660     }
661   }
662   *osamp = 0;
663   len = *isamp? sox_write(ofile->ft, ibuf, *isamp) : 0;
664   output_samples += len / ofile->ft->signal.channels;
665   output_eof = (len != *isamp) ? sox_true: sox_false;
666   if (len != *isamp) {
667     if (ofile->ft->sox_errno)
668       lsx_fail("`%s' %s: %s", ofile->ft->filename,
669           ofile->ft->sox_errstr, sox_strerror(ofile->ft->sox_errno));
670     return SOX_EOF;
671   }
672   return SOX_SUCCESS;
673 }
674 
675 static sox_effect_handler_t const * output_effect_fn(void)
676 {
677   static sox_effect_handler_t handler = {"output", 0, SOX_EFF_MCHAN |
678     SOX_EFF_MODIFY | SOX_EFF_PREC, NULL, ostart, output_flow, NULL, NULL, NULL, 0
679   };
680   return &handler;
681 }
682 
683 static void auto_effect(sox_effects_chain_t *, char const *, int, char **,
684     sox_signalinfo_t *, int *);
685 
686 static int add_effect(sox_effects_chain_t * chain, sox_effect_t * effp,
687     sox_signalinfo_t * in, sox_signalinfo_t const * out, int * guard) {
688   int no_guard = -1;
689   switch (*guard) {
690     case 0: if (!(effp->handler.flags & SOX_EFF_GAIN)) {
691       char * arg = "-h";
692       auto_effect(chain, "gain", 1, &arg, in, &no_guard);
693       ++*guard;
694     }
695     break;
696     case 1: if (effp->handler.flags & SOX_EFF_GAIN) {
697       char * arg = "-r";
698       auto_effect(chain, "gain", 1, &arg, in, &no_guard);
699       --*guard;
700     }
701     break;
702     case 2: if (!(effp->handler.flags & SOX_EFF_MODIFY)) {
703       lsx_warn("%s: effects that modify audio should not follow dither",
704         effp->handler.name);
705     }
706     break;
707   }
708   return sox_add_effect(chain, effp, in, out);
709 }
710 
711 static void auto_effect(sox_effects_chain_t *chain, char const *name, int argc,
712     char *argv[], sox_signalinfo_t *signal, int * guard)
713 {
714   sox_effect_t * effp;
715 
716   effp = sox_create_effect(sox_find_effect(name)); /* Should always succeed. */
717 
718   if (sox_effect_options(effp, argc, argv) == SOX_EOF)
719     exit(1); /* The failing effect should have displayed an error message */
720 
721   if (add_effect(chain, effp, signal, &ofile->ft->signal, guard) != SOX_SUCCESS)
722     exit(2); /* The effects chain should have displayed an error message */
723   free(effp);
724 }
725 
726 /* add_eff_chain() - NOTE: this only adds memory for one
727  * additional effects chain beyond value of eff_chain_count.  It
728  * does not unconditionally increase size of effects chain.
729  */
730 static void add_eff_chain(void)
731 {
732   lsx_revalloc(user_effargs, eff_chain_count+1);
733   user_effargs[eff_chain_count] = lsx_malloc(sizeof(**user_effargs));
734 
735   lsx_revalloc(user_effargs_size, eff_chain_count+1);
736   user_effargs_size[eff_chain_count] = 0;
737   lsx_revalloc(nuser_effects, eff_chain_count+1);
738   nuser_effects[eff_chain_count] = 0;
739 } /* add_eff_chain */
740 
741 /* free_eff_chain() - the inverse of add_eff_chain().  Frees
742  * one effects chain (with index eff_chain_count) such that
743  * there are eff_chain_count left, the last having index
744  * eff_chain_count-1.
745  */
746 static void free_eff_chain(void)
747 {
748   size_t j;
749   int k;
750   for (j = 0; j < nuser_effects[eff_chain_count]; j++)
751   {
752     free(user_effargs[eff_chain_count][j].name);
753     user_effargs[eff_chain_count][j].name = NULL;
754     for (k = 0; k < user_effargs[eff_chain_count][j].argc; k++)
755     {
756       free(user_effargs[eff_chain_count][j].argv[k]);
757       user_effargs[eff_chain_count][j].argv[k] = NULL;
758     }
759     user_effargs[eff_chain_count][j].argc = 0;
760     free(user_effargs[eff_chain_count][j].argv);
761     user_effargs[eff_chain_count][j].argv = NULL;
762     user_effargs[eff_chain_count][j].argv_size = 0;
763   }
764   nuser_effects[eff_chain_count] = 0;
765   free(user_effargs[eff_chain_count]);
766 } /* free_eff_chain */
767 
768 static void delete_eff_chains(void)
769 {
770   while (eff_chain_count > 0) {
771     eff_chain_count--;
772     free_eff_chain();
773   }
774   free(user_effargs);
775   free(user_effargs_size);
776   free(nuser_effects);
777   user_effargs = NULL;
778   user_effargs_size = NULL;
779   nuser_effects = NULL;
780 } /* delete_eff_chains */
781 
782 static sox_bool is_pseudo_effect(const char *s)
783 {
784   if (s)
785   if (strcmp("newfile", s) == 0 ||
786       strcmp("restart", s) == 0 ||
787       strcmp(":", s) == 0)
788     return sox_true;
789   return sox_false;
790 } /* is_pseudo_effect */
791 
792 static void parse_effects(int argc, char ** argv)
793 {
794   while (optstate.ind < argc) {
795     size_t eff_offset, j;
796     int newline_mode = 0;
797 
798     eff_offset = nuser_effects[eff_chain_count];
799     if (eff_offset == user_effargs_size[eff_chain_count]) {
800       size_t i = user_effargs_size[eff_chain_count];
801       user_effargs_size[eff_chain_count] += EFFARGS_STEP;
802       lsx_revalloc(user_effargs[eff_chain_count], user_effargs_size[eff_chain_count]);
803       for (; i < user_effargs_size[eff_chain_count]; i++) {
804         user_effargs[eff_chain_count][i].argv = NULL;
805         user_effargs[eff_chain_count][i].argv_size = 0;
806       }
807     }
808 
809     /* pseudo-effect ":" is used to create a new effects chain */
810     if (strcmp(argv[optstate.ind], ":") == 0)
811     {
812       /* Only create a new chain if current one has effects.
813        * Error checking will be done when loop is restarted.
814        */
815       if (nuser_effects[eff_chain_count] != 0)
816       {
817         eff_chain_count++;
818         add_eff_chain();
819       }
820       optstate.ind++;
821       continue;
822     }
823 
824     if (strcmp(argv[optstate.ind], "newfile") == 0)
825     {
826       /* Start a new effect chain for newfile if user doesn't
827        * manually do it.  Restart loop without advancing
828        * optstate.ind to do error checking.
829        */
830       if (nuser_effects[eff_chain_count] != 0)
831       {
832         eff_chain_count++;
833         add_eff_chain();
834         continue;
835       }
836       newline_mode = 1;
837       output_method = sox_multiple;
838     }
839     else if (strcmp(argv[optstate.ind], "restart") == 0)
840     {
841       /* Start a new effect chain for restart if user doesn't
842        * manually do it.  Restart loop without advancing
843        * optstate.ind to do error checking.
844        */
845       if (nuser_effects[eff_chain_count] != 0)
846       {
847         eff_chain_count++;
848         add_eff_chain();
849         continue;
850       }
851       newline_mode = 1;
852     }
853 
854     /* Name should always be correct! */
855     user_effargs[eff_chain_count][eff_offset].name = lsx_strdup(argv[optstate.ind]);
856     optstate.ind++;
857     for (j = 0; j < (size_t)(argc - optstate.ind) && !sox_find_effect(argv[optstate.ind + j]) &&
858          !is_pseudo_effect(argv[optstate.ind + j]); ++j) {
859       if (j >= user_effargs[eff_chain_count][eff_offset].argv_size) {
860         user_effargs[eff_chain_count][eff_offset].argv_size += EFFARGS_STEP;
861         lsx_revalloc(user_effargs[eff_chain_count][eff_offset].argv,
862             user_effargs[eff_chain_count][eff_offset].argv_size);
863       }
864       user_effargs[eff_chain_count][eff_offset].argv[j] = lsx_strdup(argv[optstate.ind + j]);
865     }
866     user_effargs[eff_chain_count][eff_offset].argc = j;
867 
868     optstate.ind += j; /* Skip past the effect arguments */
869     nuser_effects[eff_chain_count]++;
870     if (newline_mode)
871     {
872       eff_chain_count++;
873       add_eff_chain();
874     }
875   }
876 } /* parse_effects */
877 
878 static char * * strtoargv(char * s, int * argc)
879 {
880   sox_bool squote = sox_false;   /* Single quote mode (') is in effect. */
881   sox_bool dquote = sox_false;   /* Double quote mode (") is in effect. */
882   sox_bool esc    = sox_false;   /* Escape mode (\) is in effect. */
883   char * t, * * argv = NULL;
884 
885   for (*argc = 0; *s;) {
886     for (; isspace(*s); ++s);    /* Skip past any (more) white space. */
887     if (*s) {                    /* Found an arg. */
888       lsx_revalloc(argv, *argc + 1);
889       argv[(*argc)++] = s;       /* Store pointer to start of arg. */
890                                  /* Find the end of the arg: */
891       for (t = s; *s && (esc || squote || dquote || !isspace(*s)); ++s)
892         if (!esc && !squote && *s == '"')
893           dquote = !dquote;      /* Toggle double quote mode. */
894         else if (!esc && !dquote && *s == '\'')
895           squote = !squote;      /* Toggle single quote mode. */
896         else if (!(esc = !esc && *s == '\\' && s[1] &&
897               (!squote && (s[1] == '"' || !dquote))))
898           *t++ = *s;             /* Only copy if not an active ', ", or \ */
899       s = *s ? s + 1 : s;        /* Skip the 1st white space char. */
900       *t = '\0';                 /* Terminate the arg. */
901     }
902   }
903   return argv;
904 }                                /* strtoargv */
905 
906 static void read_user_effects(char const *filename)
907 {
908     FILE *file = fopen(filename, "r");
909     const size_t buffer_size_step = 1024;
910     size_t buffer_size = buffer_size_step;
911     char *s = lsx_malloc(buffer_size); /* buffer for one input line */
912     int pos = 0;
913     int argc;
914     char * * argv;
915     sox_bool last_was_colon = sox_false; /* last line read consisted of ":" only */
916 
917     /* Free any command line options and then re-initialize to
918      * starter user_effargs.
919      */
920     delete_eff_chains();
921     current_eff_chain = 0;
922     add_eff_chain();
923 
924     if (!file) {
925         lsx_fail("Cannot open effects file `%s': %s", filename, strerror(errno));
926         exit(1);
927     }
928 
929     lsx_report("Reading effects from file `%s'", filename);
930 
931     while(fgets(s + pos, (int) (buffer_size - pos), file)) {
932       int len = strlen(s + pos);
933       if (len && s[pos+len-1] == '\n')
934         s[pos+len-1] = '\0', pos = 0; /* we've read a complete line */
935       else if (len == (int)(buffer_size - pos - 1)) {
936         /* line was longer than buffer size */
937         buffer_size += buffer_size_step;
938         s = lsx_realloc(s, buffer_size);
939         pos += len;
940         continue; /* read next part */
941       } else {
942         /* something strange happened; the file might have ended
943            without a '\n', might contain '\0', or a read error
944            occurred */
945         if (ferror(file))
946           break; /* use error reporting after loop */
947         lsx_fail("Error reading effects file `%s' (not a text file?)", filename);
948         exit(1);
949       }
950 
951       last_was_colon = sox_false;
952 
953       argv = strtoargv(s, &argc);
954 
955       if (argv && argc == 1 && strcmp(argv[0], ":") == 0)
956         last_was_colon = sox_true;
957 
958       if (argv) {
959         /* Make sure first option is an effect name. */
960         if (!sox_find_effect(argv[0]) && !is_pseudo_effect(argv[0]))
961         {
962           lsx_fail("Cannot find an effect called `%s'.", argv[0]);
963           exit(1);
964         }
965 
966         /* parse_effects normally parses options from command line.
967          * Reset opt index so it thinks its back at beginning of
968          * main()'s argv[].
969          */
970         optstate.ind = 0;
971         parse_effects(argc, argv);
972 
973         /* Advance to next effect but only if current chain has been
974          * filled in.  This recovers from side affects of pseudo-effects.
975          */
976         if (nuser_effects[eff_chain_count] > 0) {
977           eff_chain_count++;
978           add_eff_chain();
979         }
980 
981         free(argv);
982       }
983     }
984     if (ferror(file)) {
985       lsx_fail("Error reading effects file `%s': %s", filename, strerror(errno));
986       exit(1);
987     }
988     fclose(file);
989     free(s);
990 
991     if (last_was_colon || eff_chain_count == 0) {
992       /* user explicitly wanted an empty last effects chain,
993          or didn't specify any chains at all */
994       eff_chain_count++;
995     } else {
996       /* there's one unneeded effects chain */
997       free_eff_chain();
998     }
999 } /* read_user_effects */
1000 
1001 /* Creates users effects and passes in user specified options.
1002  * This is done without putting anything into the effects chain
1003  * because an effect may set the effp->in_format and we may want
1004  * to copy that back into the input/combiner before opening and
1005  * inserting it.
1006  * Similarly, we may want to use effp->out_format to override the
1007  * default values of output file before we open it.
1008  * To keep things simple, we create all user effects.  Later, when
1009  * we add them, some may already be in the chain and we will need to free
1010  * them.
1011  */
1012 static void create_user_effects(void)
1013 {
1014   size_t i;
1015   sox_effect_t *effp;
1016   size_t num_effects = nuser_effects[current_eff_chain];
1017 
1018   /* extend user_efftab, if needed */
1019   if (user_efftab_size < num_effects) {
1020     user_efftab_size = num_effects;
1021     lsx_revalloc(user_efftab, num_effects);
1022   }
1023 
1024   for (i = 0; i < num_effects; i++) {
1025     effp = sox_create_effect(sox_find_effect(user_effargs[current_eff_chain][i].name));
1026 
1027     if (effp->handler.flags & SOX_EFF_DEPRECATED)
1028       lsx_warn("effect `%s' is deprecated; see sox(1) for an alternative",
1029           effp->handler.name);
1030     else if (effp->handler.flags & SOX_EFF_ALPHA)
1031       lsx_warn("effect `%s' is experimental/incomplete", effp->handler.name);
1032     else if (effp->handler.flags & SOX_EFF_INTERNAL) {
1033       lsx_fail("`%s' is a libSoX-only effect", effp->handler.name);
1034       exit(1);
1035     }
1036 
1037     /* The failing effect should have displayed an error message */
1038     if (sox_effect_options(effp, user_effargs[current_eff_chain][i].argc,
1039           user_effargs[current_eff_chain][i].argv) == SOX_EOF)
1040       exit(1);
1041 
1042     user_efftab[i] = effp;
1043   }
1044 }
1045 
1046 /* Add all user effects to the chain.  If the output effect's rate or
1047  * channel count do not match the end of the effects chain then
1048  * insert effects to correct this.
1049  *
1050  * This can be called with the input effect already in the effects
1051  * chain from a previous run.  Also, it use a pre-existing
1052  * output effect if its been saved into save_output_eff.
1053  */
1054 static void add_effects(sox_effects_chain_t *chain)
1055 {
1056   sox_signalinfo_t signal = combiner_signal;
1057   int guard = is_guarded - 1;
1058   size_t i;
1059   sox_effect_t * effp;
1060   char * rate_arg = is_player ? (play_rate_arg ? play_rate_arg : "-l") : NULL;
1061 
1062   /* 1st `effect' in the chain is the input combiner_signal.
1063    * add it only if its not there from a previous run.  */
1064   if (chain->length == 0) {
1065     effp = sox_create_effect(input_combiner_effect_fn());
1066     sox_add_effect(chain, effp, &signal, &ofile->ft->signal);
1067     free(effp);
1068   }
1069 
1070   /* Add user specified effects; stop before `dither' */
1071   for (i = 0; i < nuser_effects[current_eff_chain] &&
1072       strcmp(user_efftab[i]->handler.name, "dither"); i++) {
1073     if (add_effect(chain, user_efftab[i], &signal, &ofile->ft->signal,
1074           &guard) != SOX_SUCCESS)
1075       exit(2); /* Effects chain should have displayed an error message */
1076     free(user_efftab[i]);
1077   }
1078 
1079   /* Add auto effects if still needed at this point */
1080   if (signal.channels < ofile->ft->signal.channels &&
1081       signal.rate != ofile->ft->signal.rate)
1082     auto_effect(chain, "rate", rate_arg != NULL, &rate_arg, &signal, &guard);
1083   if (signal.channels != ofile->ft->signal.channels)
1084     auto_effect(chain, "channels", 0, NULL, &signal, &guard);
1085   if (signal.rate != ofile->ft->signal.rate)
1086     auto_effect(chain, "rate", rate_arg != NULL, &rate_arg, &signal, &guard);
1087 
1088   if (is_guarded && (do_guarded_norm || !(signal.mult && *signal.mult == 1))) {
1089     char *args[2];
1090     int no_guard = -1;
1091     args[0] = do_guarded_norm? "-nh" : guard? "-rh" : "-h";
1092     args[1] = norm_level;
1093     auto_effect(chain, "gain", norm_level ? 2 : 1, args, &signal, &no_guard);
1094     guard = 1;
1095   }
1096 
1097   if (i == nuser_effects[current_eff_chain] && !no_dither && signal.precision >
1098       ofile->ft->signal.precision && ofile->ft->signal.precision < 24)
1099     auto_effect(chain, "dither", 0, NULL, &signal, &guard);
1100 
1101   /* Add user specified effects from `dither' onwards */
1102   for (; i < nuser_effects[current_eff_chain]; i++, guard = 2) {
1103     if (add_effect(chain, user_efftab[i], &signal, &ofile->ft->signal,
1104           &guard) != SOX_SUCCESS)
1105       exit(2); /* Effects chain should have displayed an error message */
1106     free(user_efftab[i]);
1107   }
1108 
1109   if (!save_output_eff)
1110   {
1111     /* Last `effect' in the chain is the output file */
1112     effp = sox_create_effect(output_effect_fn());
1113     if (sox_add_effect(chain, effp, &signal, &ofile->ft->signal) != SOX_SUCCESS)
1114       exit(2);
1115     free(effp);
1116   }
1117   else
1118   {
1119     sox_push_effect_last(chain, save_output_eff);
1120     save_output_eff = NULL;
1121   }
1122 
1123   for (i = 0; i < chain->length; ++i) {
1124     char const * format = sox_globals.verbosity > 3?
1125       "effects chain: %-10s %7gHz %2u channels %7s %2u bits %s" :
1126       "effects chain: %-10s %7gHz %2u channels";
1127     sox_effect_t const * effp = &chain->effects[i][0];
1128     lsx_report(format, effp->handler.name, effp->out_signal.rate,
1129         effp->out_signal.channels,
1130         (effp->handler.flags & SOX_EFF_MCHAN)? "(multi)" : "",
1131         effp->out_signal.precision,
1132         effp->out_signal.length != SOX_UNKNOWN_LEN ?
1133           str_time(effp->out_signal.length/effp->out_signal.channels/effp->out_signal.rate) :
1134           "unknown length"
1135         );
1136   }
1137 }
1138 
1139 static int advance_eff_chain(void)
1140 {
1141   sox_bool reuse_output = sox_true;
1142 
1143   very_first_effchain = sox_false;
1144 
1145   /* If input file reached EOF then delete all effects in current
1146    * chain and restart the current chain.
1147    *
1148    * This is only used with sox_sequence combine mode even though
1149    * we do not specifically check for that method.
1150    */
1151   if (input_eof)
1152     sox_delete_effects(effects_chain);
1153   else
1154   {
1155     /* If user requested to restart this effect chain then
1156      * do not advance to next.  Usually, this is because
1157      * an option to current effect was changed.
1158      */
1159     if (user_restart_eff)
1160       user_restart_eff = sox_false;
1161     /* Effect chain stopped so advance to next effect chain but
1162      * quite if no more chains exist.
1163      */
1164     else if (++current_eff_chain >= eff_chain_count)
1165       return SOX_EOF;
1166 
1167     while (nuser_effects[current_eff_chain] == 1 &&
1168            is_pseudo_effect(user_effargs[current_eff_chain][0].name))
1169     {
1170       if (strcmp("newfile", user_effargs[current_eff_chain][0].name) == 0)
1171       {
1172         if (++current_eff_chain >= eff_chain_count)
1173           return SOX_EOF;
1174         reuse_output = sox_false;
1175       }
1176       else if (strcmp("restart", user_effargs[current_eff_chain][0].name) == 0)
1177         current_eff_chain = 0;
1178     }
1179 
1180     if (reuse_output)
1181       save_output_eff = sox_pop_effect_last(effects_chain);
1182 
1183     while (effects_chain->length > 1)
1184       sox_delete_effect_last(effects_chain);
1185   }
1186   return SOX_SUCCESS;
1187 } /* advance_eff_chain */
1188 
1189 static uint64_t total_clips(void)
1190 {
1191   size_t i;
1192   uint64_t clips = 0;
1193   for (i = 0; i < file_count; ++i)
1194     clips += files[i]->ft->clips + files[i]->volume_clips;
1195   return clips + mixing_clips + sox_effects_clips(effects_chain);
1196 }
1197 
1198 static sox_bool since(struct timeval * then, double secs, sox_bool always_reset)
1199 {
1200   sox_bool ret;
1201   struct timeval now;
1202   time_t d;
1203   gettimeofday(&now, NULL);
1204   d = now.tv_sec - then->tv_sec;
1205   ret = d > ceil(secs) || now.tv_usec - then->tv_usec + d * TIME_FRAC >= secs * TIME_FRAC;
1206   if (ret || always_reset)
1207     *then = now;
1208   return ret;
1209 }
1210 
1211 #define MIN_HEADROOM 6.
1212 static double min_headroom = MIN_HEADROOM;
1213 
1214 static char const * vu(unsigned channel)
1215 {
1216   static struct timeval then;
1217   static char const * const text[][2] = {
1218     /* White: 2dB steps */
1219     {"", ""}, {"-", "-"}, {"=", "="}, {"-=", "=-"},
1220     {"==", "=="}, {"-==", "==-"}, {"===", "==="}, {"-===", "===-"},
1221     {"====", "===="}, {"-====", "====-"}, {"=====", "====="},
1222     {"-=====", "=====-"}, {"======", "======"},
1223     /* Red: 1dB steps */
1224     {"!=====", "=====!"},
1225   };
1226   int const red = 1, white = array_length(text) - red;
1227   double const MAX = SOX_SAMPLE_MAX, MIN = SOX_SAMPLE_MIN;
1228   double linear = max(omax[channel] / MAX, omin[channel] / MIN);
1229   double dB = linear_to_dB(linear);
1230   int vu_dB = linear? floor(2 * white + red + dB) : 0;
1231   int index = vu_dB < 2 * white? max(vu_dB / 2, 0) : min(vu_dB - white, red + white - 1);
1232   omax[channel] = omin[channel] = 0;
1233   if (-dB < min_headroom) {
1234     gettimeofday(&then, NULL);
1235     min_headroom = -dB;
1236   }
1237   else if (since(&then, 3., sox_false))
1238     min_headroom = -dB;
1239 
1240   return text[index][channel];
1241 }
1242 
1243 static char * headroom(void)
1244 {
1245   if (min_headroom < MIN_HEADROOM) {
1246     static char buff[10];
1247     unsigned h = (unsigned)(min_headroom * 10);
1248     sprintf(buff, "Hd:%u.%u", h /10, h % 10);
1249     return buff;
1250   }
1251   return "      ";
1252 }
1253 
1254 static void display_status(sox_bool all_done)
1255 {
1256   static struct timeval then;
1257   if (!show_progress)
1258     return;
1259   if (all_done || since(&then, .1, sox_false)) {
1260     double read_time = (double)read_wide_samples / combiner_signal.rate;
1261     double left_time = 0, in_time = 0, percentage = 0;
1262 
1263     if (input_wide_samples) {
1264       in_time = (double)input_wide_samples / combiner_signal.rate;
1265       left_time = max(in_time - read_time, 0);
1266       percentage = max(100. * read_wide_samples / input_wide_samples, 0);
1267     }
1268     fprintf(stderr, "\rIn:%-5s %s [%s] Out:%-5s [%6s|%-6s] %s Clip:%-5s",
1269       lsx_sigfigs3p(percentage), str_time(read_time), str_time(left_time),
1270       lsx_sigfigs3((double)output_samples),
1271       vu(0), vu(1), headroom(), lsx_sigfigs3((double)total_clips()));
1272   }
1273   if (all_done)
1274     fputc('\n', stderr);
1275 }
1276 
1277 #ifdef HAVE_TERMIOS_H
1278 static int kbhit(void)
1279 {
1280   struct timeval time_val = {0, 0};
1281   fd_set fdset;
1282 
1283   FD_ZERO(&fdset);
1284   FD_SET(fileno(stdin), &fdset);
1285   select(fileno(stdin) + 1, &fdset, NULL, NULL, &time_val);
1286   return FD_ISSET(fileno(stdin), &fdset);
1287 }
1288 #elif !defined(HAVE_CONIO_H)
1289 #define kbhit() 0
1290 #endif
1291 
1292 #ifdef HAVE_SOUNDCARD_H
1293 #include <sys/ioctl.h>
1294 static void adjust_volume(int delta)
1295 {
1296   char * from_env = getenv("MIXERDEV");
1297   int vol1 = 0, vol2 = 0, fd = open(from_env? from_env : "/dev/mixer", O_RDWR);
1298   if (fd >= 0) {
1299     if (ioctl(fd, MIXER_READ(SOUND_MIXER_PCM), &vol1) != -1) {
1300       int side1 = vol1 & 0xff, side2 = (vol1 >> 8) & 0xff;
1301       delta = delta < 0?  max(delta, -min(side1, side2)) :
1302           min(delta, 100 - max(side1, side2));
1303       vol2 = ((side2 + delta) << 8) + side1 + delta;
1304       lsx_debug("%04x %04x", vol1, vol2);
1305       if (vol1 != vol2 && ioctl(fd, MIXER_WRITE(SOUND_MIXER_PCM), &vol2) < 0)
1306         vol2 = vol1;
1307     }
1308     close(fd);
1309   }
1310   if (vol1 == vol2)
1311     putc('\a', stderr);
1312 }
1313 #elif defined(HAVE_AUDIOIO_H)
1314 static void adjust_volume(int delta)
1315 {
1316   int vol1 = 0, vol2 = 0, fd = fileno((FILE*)ofile->ft->fp);
1317   if (fd >= 0) {
1318     audio_info_t audio_info;
1319     if (ioctl(fd, AUDIO_GETINFO, &audio_info) >= 0) {
1320       vol1 = (audio_info.play.gain * 100 + (AUDIO_MAX_GAIN >> 1)) / AUDIO_MAX_GAIN;
1321       vol2 = range_limit(vol1 + delta, 0, 100);
1322       AUDIO_INITINFO(&audio_info);
1323       audio_info.play.gain = (vol2 * AUDIO_MAX_GAIN + 50) / 100;
1324       audio_info.output_muted = 0;
1325       lsx_debug("%04x %04x", vol1, vol2);
1326       if (vol1 != vol2 && ioctl(fd, AUDIO_SETINFO, &audio_info) < 0)
1327         vol2 = vol1;
1328     }
1329   }
1330   if (vol1 == vol2)
1331     putc('\a', stderr);
1332 }
1333 #else
1334 static void adjust_volume(int delta)
1335 {
1336   (void)delta;
1337   putc('\a', stderr);
1338 }
1339 #endif
1340 
1341 static int update_status(sox_bool all_done, void * client_data)
1342 {
1343   (void)client_data;
1344   if (interactive) while (kbhit()) {
1345 #ifdef HAVE_CONIO_H
1346     int ch = _getch();
1347 #else
1348     int ch = getchar();
1349 #endif
1350 
1351 #ifdef MORE_INTERACTIVE
1352     if (files[current_input]->ft->handler.seek &&
1353         files[current_input]->ft->seekable)
1354     {
1355       if (ch == '>')
1356       {
1357         uint64_t jump = files[current_input]->ft->signal.rate*30; /* 30 sec. */
1358         if (input_wide_samples == 0 ||
1359                   read_wide_samples+jump < input_wide_samples) {
1360           read_wide_samples += jump;
1361           sox_seek(files[current_input]->ft, read_wide_samples,
1362                    SOX_SEEK_SET);
1363           /* FIXME: Do something if seek fails. */
1364         }
1365       }
1366       if (ch == '<')
1367       {
1368         uint64_t jump = files[current_input]->ft->signal.rate*30; /* 30 sec. */
1369         read_wide_samples = jump < read_wide_samples ?
1370             read_wide_samples-jump : 0;
1371         sox_seek(files[current_input]->ft, read_wide_samples,
1372                  SOX_SEEK_SET);
1373         /* FIXME: Do something if seek fails. */
1374       }
1375     }
1376     if (ch == 'R')
1377     {
1378       /* Not very useful, eh!  Sample though of the place you
1379        * could change the value to effects options
1380        * like vol or speed or remix.
1381        * Modify values in user_effargs[current_eff_chain][xxx]
1382        * and then chain will be drain()ed and restarted whence
1383        * this function is existed.
1384        */
1385       user_restart_eff = sox_true;
1386     }
1387 #endif
1388     switch (ch) {
1389       case 'V': adjust_volume(+7); break;
1390       case 'v': adjust_volume(-7); break;
1391     }
1392   }
1393 
1394   display_status(all_done || user_abort);
1395   return (user_abort || user_restart_eff) ? SOX_EOF : SOX_SUCCESS;
1396 }
1397 
1398 static void optimize_trim(void)
1399 {
1400   /* Speed hack.  If the "trim" effect is the first effect then peek inside its
1401    * "effect descriptor" and see what the start location is.  This has to be
1402    * done after its start() is called to have the correct location.  Also, only
1403    * do this when only working with one input file.  This is because the logic
1404    * to do it for multiple files is complex and probably never used.  The same
1405    * is true for a restarted or additional effects chain (relative positioning
1406    * within the file and possible samples still buffered in the input effect
1407    * would have to be taken into account).  This hack is a huge time savings
1408    * when trimming gigs of audio data into managable chunks.  */
1409   if (input_count == 1 && very_first_effchain && effects_chain->length > 1 &&
1410       strcmp(effects_chain->effects[1][0].handler.name, "trim") == 0) {
1411     if (files[0]->ft->handler.seek && files[0]->ft->seekable){
1412       uint64_t offset = sox_trim_get_start(&effects_chain->effects[1][0]);
1413       if (offset && sox_seek(files[0]->ft, offset, SOX_SEEK_SET) == SOX_SUCCESS) {
1414         read_wide_samples = offset / files[0]->ft->signal.channels;
1415         /* Assuming a failed seek stayed where it was.  If the seek worked then
1416          * reset the start location of trim so that it thinks user didn't
1417          * request a skip.  */
1418         sox_trim_clear_start(&effects_chain->effects[1][0]);
1419         lsx_debug("optimize_trim successful");
1420       }
1421     }
1422   }
1423 }
1424 
1425 static sox_bool overwrite_permitted(char const * filename)
1426 {
1427   char c;
1428 
1429   if (!no_clobber) {
1430     lsx_report("Overwriting `%s'", filename);
1431     return sox_true;
1432   }
1433   lsx_warn("Output file `%s' already exists", filename);
1434   if (!stdin_is_a_tty)
1435     return sox_false;
1436   do fprintf(stderr, "%s sox: overwrite `%s' (y/n)? ", myname, filename);
1437   while (scanf(" %c%*[^\n]", &c) != 1 || !strchr("yYnN", c));
1438   return c == 'y' || c == 'Y';
1439 }
1440 
1441 static char *fndup_with_count(const char *filename, size_t count)
1442 {
1443     char *expand_fn, *efn;
1444     const char *fn, *ext, *end;
1445     sox_bool found_marker = sox_false;
1446 
1447     fn = filename;
1448 
1449     efn = expand_fn = lsx_malloc((size_t)FILENAME_MAX);
1450 
1451     /* Find extension in case user didn't specify a substitution
1452      * marker.
1453      */
1454     end = ext = filename + strlen(filename);
1455     while (ext > filename && *ext != '.')
1456         ext--;
1457 
1458     /* In case extension not found, point back to end of string to do less
1459      * copying later.
1460      */
1461     if (*ext != '.')
1462         ext = end;
1463 
1464     while (fn < end)
1465     {
1466         /* Look for %n. If found, replace with count.  Can specify an
1467          * option width of 1-9.
1468          */
1469         if (*fn == '%')
1470         {
1471             char width = 0;
1472             fn++;
1473             if (*fn >= '1' && *fn <= '9')
1474             {
1475                 width = *fn++;
1476             }
1477             if (*fn == 'n')
1478             {
1479                 char format[5];
1480 
1481                 found_marker = sox_true;
1482 
1483                 if (width)
1484                 {
1485 					sprintf(format, "%%0%cd", width);
1486                 }
1487 				else
1488 				{
1489                     strcpy(format, "%02d");
1490 				}
1491 
1492                 efn += sprintf(efn, format, count);
1493                 fn++;
1494             }
1495             else
1496                 *efn++ = *fn++;
1497         }
1498         else
1499             *efn++ = *fn++;
1500     }
1501 
1502     *efn = 0;
1503 
1504     /* If user didn't tell us what to do then default to putting
1505      * the count right before file extension.
1506      */
1507     if (!found_marker)
1508     {
1509         efn -= strlen (ext);
1510 
1511         sprintf(efn, "%03lu", (unsigned long)count);
1512         efn = efn + 3;
1513         strcat(efn, ext);
1514     }
1515 
1516     return expand_fn;
1517 }
1518 
1519 static void open_output_file(void)
1520 {
1521   double factor;
1522   int i;
1523   sox_comments_t p = ofile->oob.comments;
1524   sox_oob_t oob = files[0]->ft->oob;
1525   char *expand_fn;
1526 
1527   /* Skip opening file if we are not recreating output effect */
1528   if (save_output_eff)
1529     return;
1530 
1531   oob.comments = sox_copy_comments(files[0]->ft->oob.comments);
1532 
1533   if (!oob.comments && !p)
1534     sox_append_comment(&oob.comments, "Processed by SoX");
1535   else if (p) {
1536     if (!(*p)[0]) {
1537       sox_delete_comments(&oob.comments);
1538       ++p;
1539     }
1540     while (*p)
1541       sox_append_comment(&oob.comments, *p++);
1542   }
1543 
1544   /* Copy loop info, resizing appropriately it's in samples, so # channels
1545    * don't matter FIXME: This doesn't work for multi-file processing or effects
1546    * that change file length.  */
1547   factor = (double) ofile->signal.rate / combiner_signal.rate;
1548   for (i = 0; i < SOX_MAX_NLOOPS; i++) {
1549     oob.loops[i].start = oob.loops[i].start * factor;
1550     oob.loops[i].length = oob.loops[i].length * factor;
1551   }
1552 
1553   if (output_method == sox_multiple)
1554     expand_fn = fndup_with_count(ofile->filename, ++output_count);
1555   else
1556     expand_fn = lsx_strdup(ofile->filename);
1557   ofile->ft = sox_open_write(expand_fn, &ofile->signal, &ofile->encoding,
1558       ofile->filetype, &oob, overwrite_permitted);
1559   sox_delete_comments(&oob.comments);
1560   free(expand_fn);
1561 
1562   if (!ofile->ft)
1563     /* sox_open_write() will call lsx_warn for most errors.
1564      * Rely on that printing something. */
1565     exit(2);
1566 
1567   /* If whether to enable the progress display (similar to that of ogg123) has
1568    * not been specified by the user, auto turn on when outputting to an audio
1569    * device: */
1570   if (show_progress == sox_option_default)
1571     show_progress = (ofile->ft->handler.flags & SOX_FILE_DEVICE) != 0 &&
1572                     (ofile->ft->handler.flags & SOX_FILE_PHONY) == 0;
1573 
1574   report_file_info(ofile);
1575 }
1576 
1577 static void sigint(int s)
1578 {
1579   static struct timeval then;
1580   if (input_count > 1 && show_progress && s == SIGINT &&
1581       is_serial(combine_method) && since(&then, 1.0, sox_true))
1582   {
1583     signal(SIGINT, sigint);
1584     user_skip = sox_true;
1585   }
1586   else user_abort = sox_true;
1587 }
1588 
1589 static void calculate_combiner_signal_parameters(void)
1590 {
1591   size_t i;
1592 
1593   /* If user didn't specify # of channels then see if an effect
1594    * is specifying them.  This is of most use currently with the
1595    * synth effect were user can use null input handler and specify
1596    * channel counts directly in effect.  Forcing to use -c with
1597    * -n isn't as convenient.
1598    */
1599   for (i = 0; i < input_count; i++) {
1600     size_t j;
1601     for (j =0; j < nuser_effects[current_eff_chain] &&
1602                !files[i]->ft->signal.channels; ++j)
1603       files[i]->ft->signal.channels = user_efftab[j]->in_signal.channels;
1604     /* For historical reasons, default to one channel if not specified. */
1605     if (!files[i]->ft->signal.channels)
1606       files[i]->ft->signal.channels = 1;
1607   }
1608 
1609   /* Set the combiner output signal attributes to those of the 1st/next input
1610    * file.  If we are in sox_sequence mode then we don't need to check the
1611    * attributes of the other inputs, otherwise, it is mandatory that all input
1612    * files have the same sample rate, and for sox_concatenate, it is mandatory
1613    * that they have the same number of channels, otherwise, the number of
1614    * channels at the output of the combiner is calculated according to the
1615    * combiner mode. */
1616   combiner_signal = files[current_input]->ft->signal;
1617   if (combine_method == sox_sequence) {
1618     /* Report all input files; do this only the 1st time process() is called: */
1619     if (!current_input) for (i = 0; i < input_count; i++)
1620       report_file_info(files[i]);
1621     combiner_signal.length = SOX_UNKNOWN_LEN;
1622   } else {
1623     size_t total_channels = 0;
1624     size_t min_channels = SOX_SIZE_MAX;
1625     size_t max_channels = 0;
1626     size_t min_rate = SOX_SIZE_MAX;
1627     size_t max_rate = 0;
1628     uint64_t total_length = 0, max_length_ws = 0;
1629 
1630     /* Report all input files and gather info on differing rates & numbers of
1631      * channels, and on the resulting output audio length: */
1632     for (i = 0; i < input_count; i++) {
1633       report_file_info(files[i]);
1634       total_channels += files[i]->ft->signal.channels;
1635       min_channels = min(min_channels, files[i]->ft->signal.channels);
1636       max_channels = max(max_channels, files[i]->ft->signal.channels);
1637       min_rate     = min(min_rate    , files[i]->ft->signal.rate);
1638       max_rate     = max(max_rate    , files[i]->ft->signal.rate);
1639       max_length_ws = files[i]->ft->signal.length ?
1640           max(max_length_ws, files[i]->ft->signal.length / files[i]->ft->signal.channels) :
1641           SOX_UNKNOWN_LEN;
1642       if (total_length != SOX_UNKNOWN_LEN && files[i]->ft->signal.length)
1643         total_length += files[i]->ft->signal.length;
1644       else
1645         total_length = SOX_UNKNOWN_LEN;
1646     }
1647 
1648     /* Check for invalid/unusual rate or channel combinations: */
1649     if (min_rate != max_rate)
1650       lsx_fail("Input files must have the same sample-rate");
1651       /* Don't exit quite yet; give the user any other message 1st */
1652     if (min_channels != max_channels) {
1653       if (combine_method == sox_concatenate) {
1654         lsx_fail("Input files must have the same # channels");
1655         exit(1);
1656       } else if (combine_method != sox_merge)
1657         lsx_warn("Input files don't have the same # channels");
1658     }
1659     if (min_rate != max_rate)
1660       exit(1);
1661 
1662     /* Store the calculated # of combined channels: */
1663     combiner_signal.channels =
1664       combine_method == sox_merge? total_channels : max_channels;
1665 
1666     if (combine_method == sox_concatenate)
1667       combiner_signal.length = total_length;
1668     else if (is_parallel(combine_method))
1669       combiner_signal.length = max_length_ws != SOX_UNKNOWN_LEN ?
1670           max_length_ws * combiner_signal.channels : SOX_UNKNOWN_LEN;
1671   }
1672 } /* calculate_combiner_signal_parameters */
1673 
1674 static void calculate_output_signal_parameters(void)
1675 {
1676   sox_bool known_length = combine_method != sox_sequence;
1677   size_t i;
1678   uint64_t olen = 0;
1679 
1680   /* Report all input files and gather info on differing rates & numbers of
1681    * channels, and on the resulting output audio length: */
1682   for (i = 0; i < input_count; i++) {
1683     known_length = known_length && files[i]->ft->signal.length != SOX_UNSPEC;
1684     if (combine_method == sox_concatenate)
1685       olen += files[i]->ft->signal.length / files[i]->ft->signal.channels;
1686     else
1687       olen = max(olen, files[i]->ft->signal.length / files[i]->ft->signal.channels);
1688   }
1689 
1690   /* Determine the output file signal attributes; set from user options
1691    * if given: */
1692   ofile->signal = ofile_signal_options;
1693 
1694   /* If no user option for output rate or # of channels, set from the last
1695    * effect that sets these, or from the input combiner if there is none such */
1696   for (i = 0; i < nuser_effects[current_eff_chain] && !ofile->signal.rate; ++i)
1697     ofile->signal.rate = user_efftab[nuser_effects[current_eff_chain] - 1 - i]->out_signal.rate;
1698   for (i = 0; i < nuser_effects[current_eff_chain] && !ofile->signal.channels; ++i)
1699     ofile->signal.channels = user_efftab[nuser_effects[current_eff_chain] - 1 - i]->out_signal.channels;
1700   if (!ofile->signal.rate)
1701     ofile->signal.rate = combiner_signal.rate;
1702   if (!ofile->signal.channels)
1703     ofile->signal.channels = combiner_signal.channels;
1704 
1705   /* FIXME: comment this: */
1706   ofile->signal.precision = combiner_signal.precision;
1707 
1708   /* If any given user effect modifies the audio length, then we assume that
1709    * we don't know what the output length will be.  FIXME: in most cases,
1710    * an effect that modifies length will be able to determine by how much from
1711    * its getopts parameters, so olen should be calculable. */
1712   for (i = 0; i < nuser_effects[current_eff_chain]; i++)
1713     known_length = known_length && !(user_efftab[i]->handler.flags & SOX_EFF_LENGTH);
1714 
1715   if (!known_length)
1716     olen = 0;
1717   ofile->signal.length = (uint64_t)(olen * ofile->signal.channels * ofile->signal.rate / combiner_signal.rate + .5);
1718 }
1719 
1720 static void set_combiner_and_output_encoding_parameters(void)
1721 {
1722   /* The input encoding parameters passed to the effects chain are those of
1723    * the first input file (for each segued block if sox_sequence):*/
1724   combiner_encoding = files[current_input]->ft->encoding;
1725 
1726   /* Determine the output file encoding attributes; set from user options
1727    * if given: */
1728   ofile->encoding = ofile_encoding_options;
1729 
1730   /* Get unspecified output file encoding attributes from the input file and
1731    * set the output file to the resultant encoding if this is supported by the
1732    * output file type; if not, the output file handler should select an
1733    * encoding suitable for the output signal and its precision. */
1734   {
1735     sox_encodinginfo_t t = ofile->encoding;
1736     if (!t.encoding)
1737       t.encoding = combiner_encoding.encoding;
1738     if (!t.bits_per_sample)
1739       t.bits_per_sample = combiner_encoding.bits_per_sample;
1740     if (sox_format_supports_encoding(ofile->filename, ofile->filetype, &t))
1741       ofile->encoding = t;
1742   }
1743 }
1744 
1745 static int process(void)
1746 {         /* Input(s) -> Balancing -> Combiner -> Effects -> Output */
1747   int flow_status;
1748 
1749   create_user_effects();
1750 
1751   calculate_combiner_signal_parameters();
1752   set_combiner_and_output_encoding_parameters();
1753   calculate_output_signal_parameters();
1754   open_output_file();
1755 
1756   if (!effects_chain)
1757     effects_chain = sox_create_effects_chain(&combiner_encoding,
1758                                              &ofile->ft->encoding);
1759   add_effects(effects_chain);
1760 
1761   if (very_first_effchain)
1762     optimize_trim();
1763 
1764 #if defined(HAVE_TERMIOS_H) || defined(HAVE_CONIO_H)
1765   if (stdin_is_a_tty) {
1766     if (show_progress && is_player && !interactive) {
1767       lsx_debug("automatically entering interactive mode");
1768       interactive = sox_true;
1769     }
1770   } else if (interactive) {
1771     /* User called for interactive mode, but ... */
1772     lsx_warn("Standard input has to be a terminal for interactive mode");
1773     interactive = sox_false;
1774   }
1775 #endif
1776 #ifdef HAVE_TERMIOS_H
1777   /* Prepare terminal for interactive mode and save the original termios
1778      settings. Do this only once, otherwise the "original" settings won't
1779      be original anymore after a second call to process() (next/restarted
1780      effects chain). */
1781   if (interactive && !original_termios_saved) {
1782     struct termios modified_termios;
1783 
1784     original_termios_saved = sox_true;
1785     tcgetattr(fileno(stdin), &original_termios);
1786     modified_termios = original_termios;
1787     modified_termios.c_lflag &= ~(ICANON | ECHO);
1788     modified_termios.c_cc[VMIN] = modified_termios.c_cc[VTIME] = 0;
1789     tcsetattr(fileno(stdin), TCSANOW, &modified_termios);
1790   }
1791 #endif
1792 
1793   signal(SIGTERM, sigint); /* Stop gracefully, as soon as we possibly can. */
1794   signal(SIGINT , sigint); /* Either skip current input or behave as SIGTERM. */
1795   if (very_first_effchain) {
1796     struct timeval now;
1797     double d;
1798     gettimeofday(&now, NULL);
1799     d = now.tv_sec - load_timeofday.tv_sec + (now.tv_usec - load_timeofday.tv_usec) / TIME_FRAC;
1800     lsx_debug("start-up time = %g", d);
1801   }
1802   flow_status = sox_flow_effects(effects_chain, update_status, NULL);
1803 
1804   /* Don't return SOX_EOF if
1805    * 1) input reach EOF and there are more input files to process or
1806    * 2) output didn't return EOF (disk full?) there are more
1807    *    effect chains.
1808    * For case #2, something else must decide when to stop processing.
1809    */
1810   if ((input_eof && current_input < input_count) ||
1811       (!output_eof && current_eff_chain < eff_chain_count))
1812     flow_status = SOX_SUCCESS;
1813 
1814   return flow_status;
1815 }
1816 
1817 static void display_SoX_version(FILE * file)
1818 {
1819 #if HAVE_SYS_UTSNAME_H
1820   struct utsname uts;
1821 #endif
1822   const sox_version_info_t* info = sox_version_info();
1823 
1824   fprintf(file, "%s:      SoX v%s%s%s\n",
1825       myname,
1826       info->version,
1827       info->version_extra ? "-" : "",
1828       info->version_extra ? info->version_extra : "");
1829 
1830   if (sox_globals.verbosity > 3) {
1831     if (info->time)
1832       fprintf(file, "time:     %s\n", info->time);
1833     if (info->distro)
1834       fprintf(file, "issue:    %s\n", info->distro);
1835 #if HAVE_SYS_UTSNAME_H
1836     if (!uname(&uts))
1837       fprintf(file, "uname:    %s %s %s %s %s\n", uts.sysname, uts.nodename,
1838           uts.release, uts.version, uts.machine);
1839 #endif
1840     if (info->compiler)
1841         fprintf(file, "compiler: %s\n", info->compiler);
1842     if (info->arch)
1843         fprintf(file, "arch:     %s\n", info->arch);
1844   }
1845 }
1846 
1847 static int strcmp_p(const void *p1, const void *p2)
1848 {
1849   return strcmp(*(const char **)p1, *(const char **)p2);
1850 }
1851 
1852 static void display_supported_formats(void)
1853 {
1854   size_t i, formats;
1855   char const * * format_list;
1856   char const * const * names;
1857 
1858   sox_format_init();
1859   for (i = formats = 0; sox_format_fns[i].fn; ++i) {
1860     char const * const *names = sox_format_fns[i].fn()->names;
1861     while (*names++)
1862       formats++;
1863   }
1864   format_list = lsx_malloc(formats * sizeof(*format_list));
1865 
1866   printf("AUDIO FILE FORMATS:");
1867   for (i = formats = 0; sox_format_fns[i].fn; ++i) {
1868     sox_format_handler_t const * handler = sox_format_fns[i].fn();
1869     if (!(handler->flags & SOX_FILE_DEVICE))
1870       for (names = handler->names; *names; ++names)
1871         if (!strchr(*names, '/'))
1872           format_list[formats++] = *names;
1873   }
1874   qsort((void*)format_list, formats, sizeof(*format_list), strcmp_p);
1875   for (i = 0; i < formats; i++)
1876     printf(" %s", format_list[i]);
1877   putchar('\n');
1878 
1879   printf("PLAYLIST FORMATS: m3u pls\nAUDIO DEVICE DRIVERS:");
1880   for (i = formats = 0; sox_format_fns[i].fn; ++i) {
1881     sox_format_handler_t const * handler = sox_format_fns[i].fn();
1882     if ((handler->flags & SOX_FILE_DEVICE) && !(handler->flags & SOX_FILE_PHONY))
1883       for (names = handler->names; *names; ++names)
1884         format_list[formats++] = *names;
1885   }
1886   qsort((void*)format_list, formats, sizeof(*format_list), strcmp_p);
1887   for (i = 0; i < formats; i++)
1888     printf(" %s", format_list[i]);
1889   puts("\n");
1890 
1891   free((void*)format_list);
1892 }
1893 
1894 static void display_supported_effects(void)
1895 {
1896   size_t i;
1897   const sox_effect_handler_t *e;
1898 
1899   printf("EFFECTS:");
1900   for (i = 0; sox_effect_fns[i]; i++) {
1901     e = sox_effect_fns[i]();
1902     if (e && e->name)
1903       printf(" %s%s", e->name, (e->flags & SOX_EFF_DEPRECATED)? "*" : (e->flags & SOX_EFF_ALPHA)? "+" : (e->flags & SOX_EFF_INTERNAL)? "#" : "");
1904   }
1905   puts("\n  * Deprecated effect    + Experimental effect    # LibSoX-only effect");
1906 }
1907 
1908 static void usage(char const * message)
1909 {
1910   const sox_version_info_t * info = sox_version_info();
1911   size_t i;
1912   static char const * const lines1[] = {
1913 "SPECIAL FILENAMES (infile, outfile):",
1914 "-                        Pipe/redirect input/output (stdin/stdout); may need -t",
1915 "-d, --default-device     Use the default audio device (where available)",
1916 "-n, --null               Use the `null' file handler; e.g. with synth effect",
1917 "-p, --sox-pipe           Alias for `-t sox -'"
1918   };
1919   static char const * const linesPopen[] = {
1920 "\nSPECIAL FILENAMES (infile only):",
1921 "\"|program [options] ...\" Pipe input from external program (where supported)",
1922 "http://server/file       Use the given URL as input file (where supported)"
1923   };
1924   static char const * const lines2[] = {
1925 "",
1926 "GLOBAL OPTIONS (gopts) (can be specified at any point before the first effect):",
1927 "--buffer BYTES           Set the size of all processing buffers (default 8192)",
1928 "--clobber                Don't prompt to overwrite output file (default)",
1929 "--combine concatenate    Concatenate all input files (default for sox, rec)",
1930 "--combine sequence       Sequence all input files (default for play)",
1931 "-D, --no-dither          Don't dither automatically",
1932 "--dft-min NUM            Minimum size (log2) for DFT processing (default 10)",
1933 "--effects-file FILENAME  File containing effects and options",
1934 "-G, --guard              Use temporary files to guard against clipping",
1935 "-h, --help               Display version number and usage information",
1936 "--help-effect NAME       Show usage of effect NAME, or NAME=all for all",
1937 "--help-format NAME       Show info on format NAME, or NAME=all for all",
1938 "--i, --info              Behave as soxi(1)",
1939 "--input-buffer BYTES     Override the input buffer size (default: as --buffer)",
1940 "--no-clobber             Prompt to overwrite output file",
1941 "-m, --combine mix        Mix multiple input files (instead of concatenating)",
1942 "--combine mix-power      Mix to equal power (instead of concatenating)",
1943 "-M, --combine merge      Merge multiple input files (instead of concatenating)"
1944   };
1945   static char const * const linesMagic[] = {
1946 "--magic                  Use `magic' file-type detection"
1947   };
1948   static char const * const linesThreads[] = {
1949 "--multi-threaded         Enable parallel effects channels processing"
1950   };
1951   static char const * const lines3[] = {
1952 "--norm                   Guard (see --guard) & normalise",
1953 "--play-rate-arg ARG      Default `rate' argument for auto-resample with `play'",
1954 "--plot gnuplot|octave    Generate script to plot response of filter effect",
1955 "-q, --no-show-progress   Run in quiet mode; opposite of -S",
1956 "--replay-gain track|album|off  Default: off (sox, rec), track (play)",
1957 "-R                       Use default random numbers (same on each run of SoX)",
1958 "-S, --show-progress      Display progress while processing audio data",
1959 "--single-threaded        Disable parallel effects channels processing",
1960 "--temp DIRECTORY         Specify the directory to use for temporary files",
1961 "-T, --combine multiply   Multiply samples of corresponding channels from all",
1962 "                         input files (instead of concatenating)",
1963 "--version                Display version number of SoX and exit",
1964 "-V[LEVEL]                Increment or set verbosity level (default 2); levels:",
1965 "                           1: failure messages",
1966 "                           2: warnings",
1967 "                           3: details of processing",
1968 "                           4-6: increasing levels of debug messages",
1969 "FORMAT OPTIONS (fopts):",
1970 "Input file format options need only be supplied for files that are headerless.",
1971 "Output files will have the same format as the input file where possible and not",
1972 "overridden by any of various means including providing output format options.",
1973 "",
1974 "-v|--volume FACTOR       Input file volume adjustment factor (real number)",
1975 "--ignore-length          Ignore input file length given in header; read to EOF",
1976 "-t|--type FILETYPE       File type of audio",
1977 "-e|--encoding ENCODING   Set encoding (ENCODING may be one of signed-integer,",
1978 "                         unsigned-integer, floating-point, mu-law, a-law,",
1979 "                         ima-adpcm, ms-adpcm, gsm-full-rate)",
1980 "-b|--bits BITS           Encoded sample size in bits",
1981 "-N|--reverse-nibbles     Encoded nibble-order",
1982 "-X|--reverse-bits        Encoded bit-order",
1983 "--endian little|big|swap Encoded byte-order; swap means opposite to default",
1984 "-L/-B/-x                 Short options for the above",
1985 "-c|--channels CHANNELS   Number of channels of audio data; e.g. 2 = stereo",
1986 "-r|--rate RATE           Sample rate of audio",
1987 "-C|--compression FACTOR  Compression factor for output format",
1988 "--add-comment TEXT       Append output file comment",
1989 "--comment TEXT           Specify comment text for the output file",
1990 "--comment-file FILENAME  File containing comment text for the output file",
1991 #if HAVE_GLOB_H
1992 "--no-glob                Don't `glob' wildcard match the following filename",
1993 #endif
1994 ""};
1995 
1996   if (!(sox_globals.verbosity > 2)) {
1997     display_SoX_version(stdout);
1998     putchar('\n');
1999   }
2000 
2001   if (message)
2002     lsx_fail("%s\n", message);  /* N.B. stderr */
2003 
2004   printf("Usage summary: [gopts] [[fopts] infile]... [fopts]%s [effect [effopt]]...\n\n",
2005          sox_mode == sox_play? "" : " outfile");
2006   for (i = 0; i < array_length(lines1); ++i)
2007     puts(lines1[i]);
2008   if (info->flags & sox_version_have_popen)
2009     for (i = 0; i < array_length(linesPopen); ++i)
2010       puts(linesPopen[i]);
2011   for (i = 0; i < array_length(lines2); ++i)
2012     puts(lines2[i]);
2013   if (info->flags & sox_version_have_magic)
2014     for (i = 0; i < array_length(linesMagic); ++i)
2015       puts(linesMagic[i]);
2016   if (info->flags & sox_version_have_threads)
2017     for (i = 0; i < array_length(linesThreads); ++i)
2018       puts(linesThreads[i]);
2019   for (i = 0; i < array_length(lines3); ++i)
2020     puts(lines3[i]);
2021   display_supported_formats();
2022   display_supported_effects();
2023   printf("EFFECT OPTIONS (effopts): effect dependent; see --help-effect\n");
2024   exit(message != NULL);
2025 }
2026 
2027 static void usage_effect(char const * name)
2028 {
2029   size_t i;
2030 
2031   display_SoX_version(stdout);
2032   putchar('\n');
2033 
2034   if (strcmp("all", name) && !sox_find_effect(name)) {
2035     printf("Cannot find an effect called `%s'.\n", name);
2036     display_supported_effects();
2037   }
2038   else {
2039     printf("Effect usage:\n\n");
2040 
2041     for (i = 0; sox_effect_fns[i]; i++) {
2042       const sox_effect_handler_t *e = sox_effect_fns[i]();
2043       if (e && e->name && (!strcmp("all", name) || !strcmp(e->name, name))) {
2044         printf("%s %s\n", e->name, e->usage? e->usage : "");
2045         if (e->flags & (SOX_EFF_DEPRECATED | SOX_EFF_ALPHA | SOX_EFF_INTERNAL))
2046           putchar('\n');
2047         if (e->flags & SOX_EFF_DEPRECATED)
2048           printf("`%s' is deprecated\n", e->name);
2049         if (e->flags & SOX_EFF_ALPHA)
2050           printf("`%s' is experimental/incomplete\n", e->name);
2051         if (e->flags & SOX_EFF_INTERNAL)
2052           printf("`%s' is libSoX-only\n", e->name);
2053         printf("\n\n");
2054       }
2055     }
2056   }
2057   exit(1);
2058 }
2059 
2060 static void usage_format1(sox_format_handler_t const * f)
2061 {
2062   char const * const * names;
2063 
2064   printf("\nFormat: %s\n", f->names[0]);
2065   printf("Description: %s\n", f->description);
2066   if (f->names[1]) {
2067     printf("Also handles:");
2068     for (names = f->names + 1; *names; ++names)
2069       printf(" %s", *names);
2070     putchar('\n');
2071   }
2072   if (f->flags & SOX_FILE_CHANS) {
2073     printf("Channels restricted to:");
2074     if (f->flags & SOX_FILE_MONO) printf(" mono");
2075     if (f->flags & SOX_FILE_STEREO) printf(" stereo");
2076     if (f->flags & SOX_FILE_QUAD) printf(" quad");
2077     putchar('\n');
2078   }
2079   if (f->write_rates) {
2080     sox_rate_t const * p = f->write_rates;
2081     printf("Sample-rate restricted to:");
2082     while (*p)
2083       printf(" %g", *p++);
2084     putchar('\n');
2085   }
2086   printf("Reads: %s\n", f->startread || f->read? "yes" : "no");
2087   if (f->startwrite || f->write) {
2088     if (f->write_formats) {
2089       sox_encoding_t e;
2090       unsigned i, s;
2091 #define enc_arg(T) (T)f->write_formats[i++]
2092       i = 0;
2093       puts("Writes:");
2094       while ((e = enc_arg(sox_encoding_t)))
2095         do {
2096           s = enc_arg(unsigned);
2097           if (sox_precision(e, s)) {
2098             printf("  ");
2099             if (s)
2100               printf("%2u-bit ", s);
2101             printf("%s (%u-bit precision)\n", sox_encodings_info[e].desc, sox_precision(e, s));
2102           }
2103         } while (s);
2104       }
2105       else puts("Writes: yes");
2106     }
2107   else puts("Writes: no");
2108 }
2109 
2110 static void usage_format(char const * name)
2111 {
2112   sox_format_handler_t const * f;
2113   unsigned i;
2114 
2115   display_SoX_version(stdout);
2116 
2117   if (strcmp("all", name)) {
2118     if (!(f = sox_find_format(name, sox_false))) {
2119       printf("Cannot find a format called `%s'.\n", name);
2120       display_supported_formats();
2121     }
2122     else usage_format1(f);
2123   }
2124   else {
2125     for (i = 0; sox_format_fns[i].fn; ++i) {
2126       sox_format_handler_t const * f = sox_format_fns[i].fn();
2127       if (!(f->flags & SOX_FILE_PHONY))
2128         usage_format1(f);
2129     }
2130   }
2131   exit(1);
2132 }
2133 
2134 static void read_comment_file(sox_comments_t * comments, char const * const filename)
2135 {
2136   int c;
2137   size_t text_length = 100;
2138   char * text = lsx_malloc(text_length + 1);
2139   FILE * file = fopen(filename, "r");
2140 
2141   if (file == NULL) {
2142     lsx_fail("Cannot open comment file `%s'", filename);
2143     exit(1);
2144   }
2145   do {
2146     size_t i = 0;
2147 
2148     while ((c = getc(file)) != EOF && !strchr("\r\n", c)) {
2149       if (i == text_length)
2150         text = lsx_realloc(text, (text_length <<= 1) + 1);
2151       text[i++] = c;
2152     }
2153     if (ferror(file)) {
2154       lsx_fail("Error reading comment file `%s'", filename);
2155       exit(1);
2156     }
2157     if (i) {
2158       text[i] = '\0';
2159       sox_append_comment(comments, text);
2160     }
2161   } while (c != EOF);
2162 
2163   fclose(file);
2164   free(text);
2165 }
2166 
2167 static char const * const getoptstr =
2168   "+b:c:de:hmnpqr:t:v:xBC:DGLMNRSTV::X";
2169 
2170 static struct lsx_option_t const long_options[] = {
2171   {"add-comment"     , lsx_option_arg_required, NULL, 0},
2172   {"buffer"          , lsx_option_arg_required, NULL, 0},
2173   {"combine"         , lsx_option_arg_required, NULL, 0},
2174   {"comment-file"    , lsx_option_arg_required, NULL, 0},
2175   {"comment"         , lsx_option_arg_required, NULL, 0},
2176   {"endian"          , lsx_option_arg_required, NULL, 0},
2177   {"input-buffer"    , lsx_option_arg_required, NULL, 0},
2178   {"interactive"     , lsx_option_arg_none    , NULL, 0},
2179   {"help-effect"     , lsx_option_arg_required, NULL, 0},
2180   {"help-format"     , lsx_option_arg_required, NULL, 0},
2181   {"no-glob"         , lsx_option_arg_none    , NULL, 0},
2182   {"plot"            , lsx_option_arg_required, NULL, 0},
2183   {"replay-gain"     , lsx_option_arg_required, NULL, 0},
2184   {"version"         , lsx_option_arg_none    , NULL, 0},
2185   {"output"          , lsx_option_arg_required, NULL, 0},
2186   {"effects-file"    , lsx_option_arg_required, NULL, 0},
2187   {"temp"            , lsx_option_arg_required, NULL, 0},
2188   {"single-threaded" , lsx_option_arg_none    , NULL, 0},
2189   {"ignore-length"   , lsx_option_arg_none    , NULL, 0},
2190   {"norm"            , lsx_option_arg_optional, NULL, 0},
2191   {"magic"           , lsx_option_arg_none    , NULL, 0},
2192   {"play-rate-arg"   , lsx_option_arg_required, NULL, 0},
2193   {"clobber"         , lsx_option_arg_none    , NULL, 0},
2194   {"no-clobber"      , lsx_option_arg_none    , NULL, 0},
2195   {"multi-threaded"  , lsx_option_arg_none    , NULL, 0},
2196   {"dft-min"         , lsx_option_arg_required, NULL, 0},
2197 
2198   {"bits"            , lsx_option_arg_required, NULL, 'b'},
2199   {"channels"        , lsx_option_arg_required, NULL, 'c'},
2200   {"compression"     , lsx_option_arg_required, NULL, 'C'},
2201   {"default-device"  , lsx_option_arg_none    , NULL, 'd'},
2202   {"no-dither"       , lsx_option_arg_none    , NULL, 'D'},
2203   {"encoding"        , lsx_option_arg_required, NULL, 'e'},
2204   {"help"            , lsx_option_arg_none    , NULL, 'h'},
2205   {"null"            , lsx_option_arg_none    , NULL, 'n'},
2206   {"no-show-progress", lsx_option_arg_none    , NULL, 'q'},
2207   {"pipe"            , lsx_option_arg_none    , NULL, 'p'},
2208   {"rate"            , lsx_option_arg_required, NULL, 'r'},
2209   {"reverse-bits"    , lsx_option_arg_none    , NULL, 'X'},
2210   {"reverse-nibbles" , lsx_option_arg_none    , NULL, 'N'},
2211   {"show-progress"   , lsx_option_arg_none    , NULL, 'S'},
2212   {"type"            , lsx_option_arg_required, NULL, 't'},
2213   {"volume"          , lsx_option_arg_required, NULL, 'v'},
2214   {"guard"           , lsx_option_arg_none    , NULL, 'G'},
2215 
2216   {NULL, 0, NULL, 0}
2217 };
2218 
2219 static int opt_index(int val)
2220 {
2221   int i;
2222   for (i = 0; long_options[i].name; ++i)
2223     if (long_options[i].val == val)
2224       return i;
2225   return -1;
2226 }
2227 
2228 static lsx_enum_item const combine_methods[] = {
2229   LSX_ENUM_ITEM(sox_,sequence)
2230   LSX_ENUM_ITEM(sox_,concatenate)
2231   LSX_ENUM_ITEM(sox_,mix)
2232   {"mix-power", sox_mix_power},
2233   LSX_ENUM_ITEM(sox_,merge)
2234   LSX_ENUM_ITEM(sox_,multiply)
2235   {0, 0}};
2236 
2237 enum {ENDIAN_little, ENDIAN_big, ENDIAN_swap};
2238 static lsx_enum_item const endian_options[] = {
2239   LSX_ENUM_ITEM(ENDIAN_,little)
2240   LSX_ENUM_ITEM(ENDIAN_,big)
2241   LSX_ENUM_ITEM(ENDIAN_,swap)
2242   {0, 0}};
2243 
2244 static lsx_enum_item const plot_methods[] = {
2245   LSX_ENUM_ITEM(sox_plot_,off)
2246   LSX_ENUM_ITEM(sox_plot_,octave)
2247   LSX_ENUM_ITEM(sox_plot_,gnuplot)
2248   LSX_ENUM_ITEM(sox_plot_,data)
2249   {0, 0}};
2250 
2251 enum {
2252   encoding_signed_integer, encoding_unsigned_integer, encoding_floating_point,
2253   encoding_ms_adpcm, encoding_ima_adpcm, encoding_oki_adpcm,
2254   encoding_gsm_full_rate, encoding_u_law, encoding_a_law};
2255 
2256 static lsx_enum_item const encodings[] = {
2257   {"signed-integer", encoding_signed_integer},
2258   {"unsigned-integer", encoding_unsigned_integer},
2259   {"floating-point", encoding_floating_point},
2260   {"ms-adpcm", encoding_ms_adpcm},
2261   {"ima-adpcm", encoding_ima_adpcm},
2262   {"oki-adpcm", encoding_oki_adpcm},
2263   {"gsm-full-rate", encoding_gsm_full_rate},
2264   {"u-law", encoding_u_law},
2265   {"mu-law", encoding_u_law},
2266   {"a-law", encoding_a_law},
2267   {0, 0}};
2268 
2269 static int enum_option(char const * arg, int option_index, lsx_enum_item const * items)
2270 {
2271   lsx_enum_item const * p = lsx_find_enum_text(arg, items, 0);
2272   if (p == NULL) {
2273     size_t len = 1;
2274     char * set = lsx_malloc(len);
2275     *set = 0;
2276     for (p = items; p->text; ++p) {
2277       set = lsx_realloc(set, len += 2 + strlen(p->text));
2278       strcat(set, ", "); strcat(set, p->text);
2279     }
2280     lsx_fail("--%s: `%s' is not one of: %s.",
2281         long_options[option_index].name, arg, set + 2);
2282     free(set);
2283     exit(1);
2284   }
2285   return p->value;
2286 }
2287 
2288 static char parse_gopts_and_fopts(file_t * f)
2289 {
2290   const sox_version_info_t* info = sox_version_info();
2291   while (sox_true) {
2292     int c;
2293     int i; /* sscanf silently accepts negative numbers for %u :( */
2294     char dummy;     /* To check for extraneous chars in optarg. */
2295 
2296     switch (c=lsx_getopt(&optstate)) {
2297     case -1:        /* @ one of: file-name, effect name, end of arg-list. */
2298       return '\0'; /* i.e. not device. */
2299 
2300     case 0:         /* Long options with no short equivalent. */
2301       switch (optstate.lngind) {
2302       case 0:
2303         if (optstate.arg)
2304           sox_append_comment(&f->oob.comments, optstate.arg);
2305         break;
2306 
2307       case 1:
2308 #define SOX_BUFMIN 16
2309         if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i <= SOX_BUFMIN) {
2310           lsx_fail("Buffer size `%s' must be > %d", optstate.arg, SOX_BUFMIN);
2311           exit(1);
2312         }
2313         sox_globals.bufsiz = i;
2314         break;
2315 
2316       case 2:
2317         combine_method = enum_option(optstate.arg, optstate.lngind, combine_methods);
2318         break;
2319 
2320       case 3:
2321         sox_append_comment(&f->oob.comments, "");
2322         read_comment_file(&f->oob.comments, optstate.arg);
2323         break;
2324 
2325       case 4:
2326         sox_append_comment(&f->oob.comments, "");
2327         if (*optstate.arg)
2328           sox_append_comment(&f->oob.comments, optstate.arg);
2329         break;
2330 
2331       case 5:
2332         if (f->encoding.reverse_bytes != sox_option_default || f->encoding.opposite_endian)
2333           usage("only one endian option per file is allowed");
2334         switch (enum_option(optstate.arg, optstate.lngind, endian_options)) {
2335           case ENDIAN_little: f->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; break;
2336           case ENDIAN_big: f->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; break;
2337           case ENDIAN_swap: f->encoding.opposite_endian = sox_true; break;
2338         }
2339         break;
2340 
2341       case 6:
2342         if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i <= SOX_BUFMIN) {
2343           lsx_fail("Buffer size `%s' must be > %d", optstate.arg, SOX_BUFMIN);
2344           exit(1);
2345         }
2346         sox_globals.input_bufsiz = i;
2347         break;
2348 
2349       case 7:
2350 #if defined(HAVE_TERMIOS_H) || defined(HAVE_CONIO_H)
2351         interactive = sox_true; break;
2352 #else
2353         lsx_fail("Interactive mode has not been enabled at compile time.");
2354         exit(1); break;
2355 #endif
2356       case 8: usage_effect(optstate.arg); break;
2357       case 9: usage_format(optstate.arg); break;
2358       case 10: f->no_glob = sox_true; break;
2359       case 11:
2360         sox_effects_globals.plot = enum_option(optstate.arg, optstate.lngind, plot_methods);
2361         break;
2362       case 12: replay_gain_mode = enum_option(optstate.arg, optstate.lngind, rg_modes); break;
2363       case 13: display_SoX_version(stdout); exit(0); break;
2364       case 14: break;
2365       case 15: effects_filename = lsx_strdup(optstate.arg); break;
2366       case 16: sox_globals.tmp_path = lsx_strdup(optstate.arg); break;
2367       case 17: sox_globals.use_threads = sox_false; break;
2368       case 18: f->signal.length = SOX_IGNORE_LENGTH; break;
2369       case 19: do_guarded_norm = is_guarded = sox_true;
2370         norm_level = lsx_strdup(optstate.arg);
2371         break;
2372       case 20:
2373         if (info->flags & sox_version_have_magic)
2374           sox_globals.use_magic = sox_true;
2375         else
2376           lsx_warn("this build of SoX does not include `magic'");
2377         break;
2378       case 21: play_rate_arg = lsx_strdup(optstate.arg); break;
2379       case 22: no_clobber = sox_false; break;
2380       case 23: no_clobber = sox_true; break;
2381       case 24: sox_globals.use_threads = sox_true; break;
2382       case 25:
2383         if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i < 8 || i > 16) {
2384           lsx_fail("Min DFT size must be in range 8 to 16");
2385           exit(1);
2386         }
2387         sox_globals.log2_dft_min_size = i;
2388         break;
2389       }
2390       break;
2391 
2392     case 'G': is_guarded = sox_true; break;
2393     case 'm': combine_method = sox_mix; break;
2394     case 'M': combine_method = sox_merge; break;
2395     case 'T': combine_method = sox_multiply; break;
2396 
2397     case 'R':                   /* Useful for regression testing. */
2398       sox_globals.repeatable = sox_true;
2399       break;
2400 
2401     case 'd': case 'n': case 'p':
2402       optstate.ind = optstate.ind;
2403       return c;
2404 
2405     case 'h':
2406       usage(NULL);
2407       break;
2408 
2409     case '?':
2410       usage("invalid option");              /* No return */
2411       break;
2412 
2413     case 't':
2414       f->filetype = optstate.arg;
2415       if (f->filetype[0] == '.')
2416         f->filetype++;
2417       break;
2418 
2419     case 'r': {
2420       char k = 0;
2421       size_t n = sscanf(optstate.arg, "%lf %c %c", &f->signal.rate, &k, &dummy);
2422       if (n < 1 || f->signal.rate <= 0 || (n > 1 && k != 'k') || n > 2) {
2423         lsx_fail("Rate value `%s' is not a positive number", optstate.arg);
2424         exit(1);
2425       }
2426       f->signal.rate *= k == 'k'? 1000. : 1.;
2427       break;
2428     }
2429 
2430     case 'v':
2431       if (sscanf(optstate.arg, "%lf %c", &f->volume, &dummy) != 1) {
2432         lsx_fail("Volume value `%s' is not a number", optstate.arg);
2433         exit(1);
2434       }
2435       uservolume = sox_true;
2436       if (f->volume < 0.0)
2437         lsx_report("Volume adjustment is negative; "
2438                   "this will result in a phase change");
2439       break;
2440 
2441     case 'c':
2442       if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i <= 0) {
2443         lsx_fail("Channels value `%s' is not a positive integer", optstate.arg);
2444         exit(1);
2445       }
2446       f->signal.channels = i;
2447       break;
2448 
2449     case 'C':
2450       if (sscanf(optstate.arg, "%lf %c", &f->encoding.compression, &dummy) != 1) {
2451         lsx_fail("Compression value `%s' is not a number", optstate.arg);
2452         exit(1);
2453       }
2454       break;
2455 
2456     case 'b':
2457       if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i <= 0) {
2458         lsx_fail("Bits value `%s' is not a positive integer", optstate.arg);
2459         exit(1);
2460       }
2461       f->encoding.bits_per_sample = i;
2462       break;
2463 
2464     case 'e': switch (enum_option(optstate.arg, opt_index('e'), encodings)) {
2465       case encoding_signed_integer:   f->encoding.encoding = SOX_ENCODING_SIGN2;     break;
2466       case encoding_unsigned_integer: f->encoding.encoding = SOX_ENCODING_UNSIGNED;  break;
2467       case encoding_floating_point:   f->encoding.encoding = SOX_ENCODING_FLOAT;     break;
2468       case encoding_ms_adpcm:         f->encoding.encoding = SOX_ENCODING_MS_ADPCM;  break;
2469       case encoding_ima_adpcm:        f->encoding.encoding = SOX_ENCODING_IMA_ADPCM; break;
2470       case encoding_oki_adpcm:        f->encoding.encoding = SOX_ENCODING_OKI_ADPCM; break;
2471       case encoding_gsm_full_rate:           f->encoding.encoding = SOX_ENCODING_GSM;       break;
2472       case encoding_u_law: f->encoding.encoding = SOX_ENCODING_ULAW;
2473         if (f->encoding.bits_per_sample == 0)
2474           f->encoding.bits_per_sample = 8;
2475         break;
2476       case encoding_a_law: f->encoding.encoding = SOX_ENCODING_ALAW;
2477         if (f->encoding.bits_per_sample == 0)
2478           f->encoding.bits_per_sample = 8;
2479         break;
2480       }
2481       break;
2482 
2483     case 'L': case 'B': case 'x':
2484       if (f->encoding.reverse_bytes != sox_option_default || f->encoding.opposite_endian)
2485         usage("only one endian option per file is allowed");
2486       switch (c) {
2487         case 'L': f->encoding.reverse_bytes   = MACHINE_IS_BIGENDIAN;    break;
2488         case 'B': f->encoding.reverse_bytes   = MACHINE_IS_LITTLEENDIAN; break;
2489         case 'x': f->encoding.opposite_endian = sox_true;            break;
2490       }
2491       break;
2492     case 'X': f->encoding.reverse_bits    = sox_option_yes;      break;
2493     case 'N': f->encoding.reverse_nibbles = sox_option_yes;      break;
2494 
2495     case 'S': show_progress = sox_option_yes; break;
2496     case 'q': show_progress = sox_option_no;  break;
2497     case 'D': no_dither = sox_true; break;
2498 
2499     case 'V':
2500       if (optstate.arg == NULL)
2501         ++sox_globals.verbosity;
2502       else {
2503         if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i < 0) {
2504           sox_globals.verbosity = 2;
2505           lsx_fail("Verbosity value `%s' is not a non-negative integer", optstate.arg);
2506           exit(1);
2507         }
2508         sox_globals.verbosity = (unsigned)i;
2509       }
2510       break;
2511     }
2512   }
2513 }
2514 
2515 static char const * device_name(char const * const type)
2516 {
2517   char * name = NULL, * from_env = getenv("AUDIODEV");
2518 
2519   if (!type)
2520     return NULL;
2521 
2522   if (0
2523       || !strcmp(type, "sunau")
2524       || !strcmp(type, "oss" )
2525       || !strcmp(type, "ossdsp")
2526       || !strcmp(type, "alsa")
2527       || !strcmp(type, "ao")
2528       || !strcmp(type, "sndio")
2529       || !strcmp(type, "coreaudio")
2530       || !strcmp(type, "pulseaudio")
2531       || !strcmp(type, "waveaudio")
2532       )
2533     name = "default";
2534 
2535   return name? from_env? from_env : name : NULL;
2536 }
2537 
2538 static char const * try_device(char const * name)
2539 {
2540   sox_format_handler_t const * handler = sox_find_format(name, sox_false);
2541   if (handler) {
2542     sox_format_t format, * ft = &format;
2543     lsx_debug("Looking for a default device: trying format `%s'", name);
2544     memset(ft, 0, sizeof(*ft));
2545     ft->filename = (char *)device_name(name);
2546     ft->priv = lsx_calloc(1, handler->priv_size);
2547     if (handler->startwrite(ft) == SOX_SUCCESS) {
2548       handler->stopwrite(ft);
2549       free(ft->priv);
2550       return name;
2551     }
2552     free(ft->priv);
2553   }
2554   return NULL;
2555 }
2556 
2557 static char const * set_default_device(file_t * f)
2558 {
2559   /* Default audio driver type in order of preference: */
2560   if (!f->filetype) f->filetype = getenv("AUDIODRIVER");
2561   if (!f->filetype) f->filetype = try_device("coreaudio");
2562   if (!f->filetype) f->filetype = try_device("pulseaudio");
2563   if (!f->filetype) f->filetype = try_device("alsa");
2564   if (!f->filetype) f->filetype = try_device("waveaudio");
2565   if (!f->filetype) f->filetype = try_device("sndio");
2566   if (!f->filetype) f->filetype = try_device("oss");
2567   if (!f->filetype) f->filetype = try_device("sunau");
2568   if (!f->filetype && file_count) /*!rec*/
2569     f->filetype = try_device("ao");
2570 
2571   if (!f->filetype) {
2572     lsx_fail("Sorry, there is no default audio device configured");
2573     exit(1);
2574   }
2575   return device_name(f->filetype);
2576 }
2577 
2578 static int add_file(file_t const * const opts, char const * const filename)
2579 {
2580   file_t * f = lsx_malloc(sizeof(*f));
2581 
2582   *f = *opts;
2583   if (!filename)
2584     usage("missing filename"); /* No return */
2585   f->filename = lsx_strdup(filename);
2586   files = lsx_realloc(files, (file_count + 1) * sizeof(*files));
2587   files[file_count++] = f;
2588   return 0;
2589 }
2590 
2591 #if HAVE_GLOB_H
2592 #ifndef GLOB_BRACE
2593 #define GLOB_BRACE 0
2594 #endif
2595 #ifndef GLOB_TILDE
2596 #define GLOB_TILDE 0
2597 #endif
2598 static int add_glob_file(file_t const * const opts, char const * const filename)
2599 {
2600   glob_t globbuf;
2601   size_t i;
2602 
2603   if (opts->no_glob)
2604     return add_file(opts, filename);
2605 
2606   if (glob(filename, GLOB_BRACE | GLOB_TILDE | GLOB_NOCHECK, NULL, &globbuf)) {
2607     lsx_fail("glob: %s", strerror(errno));
2608     exit(1);
2609   }
2610   for (i = 0; i < globbuf.gl_pathc; ++i)
2611     add_file(opts, globbuf.gl_pathv[i]);
2612   globfree(&globbuf);
2613   return 0;
2614 }
2615 #else
2616   #define add_glob_file add_file
2617 #endif
2618 
2619 static void init_file(file_t * f)
2620 {
2621   memset(f, 0, sizeof(*f));
2622   sox_init_encodinginfo(&f->encoding);
2623   f->volume = HUGE_VAL;
2624   f->replay_gain = HUGE_VAL;
2625 }
2626 
2627 static void parse_options_and_filenames(int argc, char **argv)
2628 {
2629   char const * env_opts = getenv(SOX_OPTS);
2630   file_t opts, opts_none;
2631   init_file(&opts), init_file(&opts_none);
2632 
2633   if (sox_mode == sox_rec)
2634     add_file(&opts, set_default_device(&opts)), init_file(&opts);
2635 
2636   if (env_opts && *env_opts) {
2637     char * * argv2, * str = lsx_malloc(strlen(argv[0]) + strlen(env_opts) + 2);
2638     int argc2;
2639     strcpy(str, argv[0]);
2640     strcat(str, " ");
2641     strcat(str, env_opts);
2642     argv2 = strtoargv(str, &argc2);
2643     lsx_getopt_init(argc2, argv2, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate);
2644     if (parse_gopts_and_fopts(&opts)) {
2645       lsx_fail("invalid option for "SOX_OPTS);
2646       exit(1);
2647     }
2648     free(str);
2649     free(argv2);
2650   }
2651 
2652   lsx_getopt_init(argc, argv, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate);
2653   for (; optstate.ind < argc && !sox_find_effect(argv[optstate.ind]); init_file(&opts)) {
2654     char c = parse_gopts_and_fopts(&opts);
2655     if (c == 'n') { /* is null file? */
2656       if (opts.filetype != NULL && strcmp(opts.filetype, "null") != 0)
2657         lsx_warn("ignoring `-t %s'.", opts.filetype);
2658       opts.filetype = "null";
2659       add_file(&opts, "");
2660     }
2661     else if (c == 'd') /* is default device? */
2662       add_file(&opts, set_default_device(&opts));
2663     else if (c == 'p') { /* is sox pipe? */
2664       if (opts.filetype != NULL && strcmp(opts.filetype, "sox") != 0)
2665         lsx_warn("ignoring `-t %s'.", opts.filetype);
2666       opts.filetype = "sox";
2667       add_file(&opts, "-");
2668     }
2669     else if (optstate.ind >= argc || sox_find_effect(argv[optstate.ind]))
2670       break;
2671     else if (!sox_is_playlist(argv[optstate.ind]))
2672       add_glob_file(&opts, argv[optstate.ind++]);
2673     else if (sox_parse_playlist((sox_playlist_callback_t)add_file, &opts, argv[optstate.ind++]) != SOX_SUCCESS)
2674       exit(1);
2675   }
2676   if (env_opts && *env_opts) {
2677     lsx_report("using "SOX_OPTS"=%s", env_opts);
2678     reported_sox_opts = sox_true;
2679   }
2680   if (sox_mode == sox_play)
2681     add_file(&opts, set_default_device(&opts));
2682   else if (memcmp(&opts, &opts_none, sizeof(opts))) /* fopts but no file */
2683     add_file(&opts, device_name(opts.filetype));
2684 }
2685 
2686 static double soxi_total;
2687 static size_t soxi_file_count;
2688 
2689 typedef enum {Full, Type, Rate, Channels, Samples, Duration, Duration_secs,
2690     Bits, Bitrate, Precision, Encoding, Annotation} soxi_t;
2691 
2692 static int soxi1(soxi_t const * type, char const * filename)
2693 {
2694   sox_format_t * ft = sox_open_read(filename, NULL, NULL, NULL);
2695   double secs;
2696   uint64_t ws;
2697   char const * text = NULL;
2698 
2699   if (!ft)
2700     return 1;
2701   ws = ft->signal.length / max(ft->signal.channels, 1);
2702   secs = (double)ws / max(ft->signal.rate, 1);
2703   ++soxi_file_count;
2704   if (soxi_total >= 0 && !ws)
2705     soxi_total = -2;
2706   if (soxi_total >= 0) soxi_total += *type == Samples? ws : secs;
2707 
2708   switch (*type) {
2709     case Type: printf("%s\n", ft->filetype); break;
2710     case Rate: printf("%g\n", ft->signal.rate); break;
2711     case Channels: printf("%u\n", ft->signal.channels); break;
2712     case Samples: if (soxi_total ==-1) printf("%" PRIu64 "\n", ws); break;
2713     case Duration: if (soxi_total ==-1) printf("%s\n", str_time(secs)); break;
2714     case Duration_secs: if (soxi_total ==-1) printf("%f\n", secs); break;
2715     case Bits: printf("%u\n", ft->encoding.bits_per_sample); break;
2716     case Bitrate: size_and_bitrate(ft, &text); puts(text? text : "0"); break;
2717     case Precision: printf("%u\n", ft->signal.precision); break;
2718     case Encoding: printf("%s\n", sox_encodings_info[ft->encoding.encoding].desc); break;
2719     case Annotation: if (ft->oob.comments) {
2720       sox_comments_t p = ft->oob.comments;
2721       do printf("%s\n", *p); while (*++p);
2722     }
2723     break;
2724     case Full: display_file_info(ft, NULL, sox_false); break;
2725   }
2726   return !!sox_close(ft);
2727 }
2728 
2729 static void soxi_usage(int return_code)
2730 {
2731   display_SoX_version(stdout);
2732   printf(
2733     "\n"
2734     "Usage: soxi [-V[level]] [-T] [-t|-r|-c|-s|-d|-D|-b|-B|-p|-e|-a] infile1 ...\n"
2735     "\n"
2736     "-V[n]\tIncrement or set verbosity level (default is 2)\n"
2737     "-T\tWith -s, -d or -D, display the total across all given files\n"
2738     "\n"
2739     "-t\tShow detected file-type\n"
2740     "-r\tShow sample-rate\n"
2741     "-c\tShow number of channels\n"
2742     ); printf(
2743     "-s\tShow number of samples (0 if unavailable)\n"
2744     "-d\tShow duration in hours, minutes and seconds (0 if unavailable)\n"
2745     "-D\tShow duration in seconds (0 if unavailable)\n"
2746     "-b\tShow number of bits per sample (0 if not applicable)\n"
2747     "-B\tShow the bitrate averaged over the whole file (0 if unavailable)\n"
2748     "-p\tShow estimated sample precision in bits\n"
2749     "-e\tShow the name of the audio encoding\n"
2750     "-a\tShow file comments (annotations) if available\n"
2751     "\n"
2752     "With no options, as much information as is available is shown for\n"
2753     "each given file.\n"
2754     );
2755   exit(return_code);
2756 }
2757 
2758 static int soxi(int argc, char * const * argv)
2759 {
2760   static char const opts[] = "trcsdDbBpea?TV::";
2761   soxi_t type = Full;
2762   int opt, num_errors = 0;
2763   sox_bool do_total = sox_false;
2764 
2765   if (argc < 2)
2766     soxi_usage(0);
2767   lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_opterr, 1, &optstate);
2768   while ((opt = lsx_getopt(&optstate)) > 0) /* act only on last option */
2769     if (opt == 'V') {
2770       int i; /* sscanf silently accepts negative numbers for %u :( */
2771       char dummy;     /* To check for extraneous chars in optstate.arg. */
2772       if (optstate.arg == NULL)
2773         ++sox_globals.verbosity;
2774       else {
2775         if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i < 0) {
2776           sox_globals.verbosity = 2;
2777           lsx_fail("Verbosity value `%s' is not a non-negative integer", optstate.arg);
2778           exit(1);
2779         }
2780         sox_globals.verbosity = (unsigned)i;
2781       }
2782     }
2783     else if (opt == 'T')
2784       do_total = sox_true;
2785     else if ((type = 1 + (strchr(opts, opt) - opts)) > Annotation)
2786       soxi_usage(1);
2787 
2788   if (type == Full)
2789     do_total = sox_true;
2790   else if (do_total && (type < Samples || type > Duration_secs)) {
2791     fprintf(stderr, "soxi: ignoring -T; n/a with other given option");
2792     do_total = sox_false;
2793   }
2794   soxi_total = -!do_total;
2795   for (; optstate.ind < argc; ++optstate.ind) {
2796     if (sox_is_playlist(argv[optstate.ind]))
2797       num_errors += (sox_parse_playlist((sox_playlist_callback_t)soxi1, &type, argv[optstate.ind]) != SOX_SUCCESS);
2798     else num_errors += soxi1(&type, argv[optstate.ind]);
2799   }
2800   if (type == Full) {
2801     if (soxi_file_count > 1 && soxi_total > 0)
2802       printf("Total Duration of %u files: %s\n", (unsigned)soxi_file_count, str_time(soxi_total));
2803   }
2804   else if (do_total) {
2805     if (soxi_total < 0)
2806       puts("0");
2807     else if (type == Duration)
2808       printf("%s\n", str_time(soxi_total));
2809     else printf("%f\n", soxi_total);
2810   }
2811   return num_errors;
2812 }
2813 
2814 static void set_replay_gain(sox_comments_t comments, file_t * f)
2815 {
2816   rg_mode rg = replay_gain_mode;
2817   int try = 2; /* Will try to find the other GAIN if preferred one not found */
2818   size_t i, n = sox_num_comments(comments);
2819 
2820   if (rg != RG_off) while (try--) {
2821     char const * target =
2822       rg == RG_track? "REPLAYGAIN_TRACK_GAIN=" : "REPLAYGAIN_ALBUM_GAIN=";
2823     for (i = 0; i < n; ++i) {
2824       if (strncasecmp(comments[i], target, strlen(target)) == 0) {
2825         f->replay_gain = atof(comments[i] + strlen(target));
2826         f->replay_gain_mode = rg;
2827         return;
2828       }
2829     }
2830     rg ^= RG_track ^ RG_album;
2831   }
2832 }
2833 
2834 static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap)
2835 {
2836   char const * const str[] = {"FAIL", "WARN", "INFO", "DBUG"};
2837   if (sox_globals.verbosity >= level) {
2838     char base_name[128];
2839     sox_basename(base_name, sizeof(base_name), filename);
2840     fprintf(stderr, "%s %s %s: ", myname, str[min(level - 1, 3)], base_name);
2841     vfprintf(stderr, fmt, ap);
2842     fprintf(stderr, "\n");
2843   }
2844 }
2845 
2846 static sox_bool cmp_comment_text(char const * c1, char const * c2)
2847 {
2848   return c1 && c2 && !strcasecmp(c1, c2);
2849 }
2850 
2851 int main(int argc, char **argv)
2852 {
2853   size_t i;
2854   char mybase[6];
2855 
2856   gettimeofday(&load_timeofday, NULL);
2857   myname = argv[0];
2858   sox_globals.output_message_handler = output_message;
2859 
2860   if (0 != sox_basename(mybase, sizeof(mybase), myname))
2861   {
2862     if (0 == lsx_strcasecmp(mybase, "play"))
2863       sox_mode = sox_play;
2864     else if (0 == lsx_strcasecmp(mybase, "rec"))
2865       sox_mode = sox_rec;
2866     else if (0 == lsx_strcasecmp(mybase, "soxi"))
2867       sox_mode = sox_soxi;
2868   }
2869 
2870   if (!sox_mode && argc > 1 &&
2871       (!strcmp(argv[1], "--i") || !strcmp(argv[1], "--info")))
2872     --argc, ++argv, sox_mode = sox_soxi;
2873 
2874   if (sox_init() != SOX_SUCCESS)
2875     exit(1);
2876 
2877   stdin_is_a_tty = isatty(fileno(stdin));
2878   errno = 0; /* Both isatty & fileno may set errno. */
2879 
2880   atexit(atexit_cleanup);
2881 
2882   if (sox_mode == sox_soxi)
2883     exit(soxi(argc, argv));
2884 
2885   parse_options_and_filenames(argc, argv);
2886 
2887   if (sox_globals.verbosity > 2)
2888     display_SoX_version(stderr);
2889 
2890   input_count = file_count ? file_count - 1 : 0;
2891 
2892   if (file_count) {
2893     sox_format_handler_t const * handler =
2894       sox_write_handler(ofile->filename, ofile->filetype, NULL);
2895     is_player = handler &&
2896       (handler->flags & SOX_FILE_DEVICE) && !(handler->flags & SOX_FILE_PHONY);
2897   }
2898 
2899   if (combine_method == sox_default)
2900     combine_method = is_player? sox_sequence : sox_concatenate;
2901 
2902   /* Allow e.g. known length processing in this case */
2903   if (combine_method == sox_sequence && input_count == 1)
2904     combine_method = sox_concatenate;
2905 
2906   /* Make sure we got at least the required # of input filenames */
2907   if (input_count < (size_t)(is_serial(combine_method) ? 1 : 2))
2908     usage("Not enough input filenames specified");
2909 
2910   /* Check for misplaced input/output-specific options */
2911   for (i = 0; i < input_count; ++i) {
2912     if (files[i]->encoding.compression != HUGE_VAL)
2913       usage("A compression factor can be given only for an output file");
2914     if (files[i]->oob.comments != NULL)
2915       usage("Comments can be given only for an output file");
2916   }
2917   if (ofile->volume != HUGE_VAL)
2918     usage("-v can be given only for an input file;\n"
2919             "\tuse the `gain' or `vol' effect to set the output file volume");
2920   if (ofile->signal.length != SOX_UNSPEC)
2921     usage("--ignore-length can be given only for an input file");
2922 
2923   signal(SIGINT, SIG_IGN); /* So child pipes aren't killed by track skip */
2924   for (i = 0; i < input_count; i++) {
2925     size_t j = input_count - 1 - i; /* Open in reverse order 'cos of rec (below) */
2926     file_t * f = files[j];
2927 
2928     /* When mixing audio, default to input side volume adjustments that will
2929      * make sure no clipping will occur.  Users probably won't be happy with
2930      * this, and will override it, possibly causing clipping to occur. */
2931     if (combine_method == sox_mix && !uservolume)
2932       f->volume = 1.0 / input_count;
2933     else if (combine_method == sox_mix_power && !uservolume)
2934       f->volume = 1.0 / sqrt((double)input_count);
2935 
2936     if (sox_mode == sox_rec && !j) {       /* Set the recording parameters: */
2937       if (input_count > 1) {               /* from the (just openned) next */
2938         f->signal = files[1]->ft->signal;  /* input file, or from the output */
2939         f->encoding = files[1]->ft->encoding;
2940       } else {
2941         f->signal = files[1]->signal;      /* file (which is not open yet). */
2942         f->encoding = files[1]->encoding;
2943       }
2944     }
2945     files[j]->ft = sox_open_read(f->filename, &f->signal, &f->encoding, f->filetype);
2946     if (!files[j]->ft)
2947       /* sox_open_read() will call lsx_warn for most errors.
2948        * Rely on that printing something. */
2949       exit(2);
2950     if (show_progress == sox_option_default &&
2951         (files[j]->ft->handler.flags & SOX_FILE_DEVICE) != 0 &&
2952         (files[j]->ft->handler.flags & SOX_FILE_PHONY) == 0)
2953       show_progress = sox_option_yes;
2954   }
2955 
2956   if (replay_gain_mode == RG_default)
2957     replay_gain_mode = is_player?
2958       input_count > 1 &&               /* Simple heuristic to determine if */
2959       cmp_comment_text(                /* replay-gain should be in album mode */
2960           sox_find_comment(files[0]->ft->oob.comments, "artist"),
2961           sox_find_comment(files[1]->ft->oob.comments, "artist")) &&
2962       cmp_comment_text(
2963           sox_find_comment(files[0]->ft->oob.comments, "album"),
2964           sox_find_comment(files[1]->ft->oob.comments, "album"))?
2965       RG_album : RG_track : RG_off;
2966 
2967   for (i = 0; i < input_count; i++)
2968     set_replay_gain(files[i]->ft->oob.comments, files[i]);
2969 
2970   signal(SIGINT, SIG_DFL);
2971 
2972   /* Loop through the rest of the arguments looking for effects */
2973   add_eff_chain();
2974   parse_effects(argc, argv);
2975   eff_chain_count++;
2976   /* Note: Purposely not calling add_eff_chain() to save some
2977    * memory although it would be more consistent to do so.
2978    */
2979 
2980   /* Not the best way for users to do this; now deprecated in favour of soxi. */
2981   if (!show_progress && !nuser_effects[current_eff_chain] &&
2982       ofile->filetype && !strcmp(ofile->filetype, "null")) {
2983     for (i = 0; i < input_count; i++)
2984       report_file_info(files[i]);
2985     exit(0);
2986   }
2987 
2988   if (!sox_globals.repeatable) {/* Re-seed PRNG? */
2989     struct timeval now;
2990     gettimeofday(&now, NULL);
2991     sox_globals.ranqd1 = (int32_t)(now.tv_sec - now.tv_usec);
2992   }
2993 
2994   /* Save things that sox_sequence needs to be reinitialised for each segued
2995    * block of input files.*/
2996   ofile_signal_options = ofile->signal;
2997   ofile_encoding_options = ofile->encoding;
2998 
2999   /* If user specified an effects filename then use that file
3000    * to load user effects.  Free any previously specified options
3001    * from the command line.
3002    */
3003   if (effects_filename)
3004   {
3005     read_user_effects(effects_filename);
3006   }
3007 
3008   while (process() != SOX_EOF && !user_abort && current_input < input_count)
3009   {
3010     if (advance_eff_chain() == SOX_EOF)
3011       break;
3012 
3013     if (!save_output_eff)
3014     {
3015       sox_close(ofile->ft);
3016       ofile->ft = NULL;
3017     }
3018   }
3019 
3020   sox_delete_effects_chain(effects_chain);
3021   delete_eff_chains();
3022 
3023   for (i = 0; i < file_count; ++i)
3024     if (files[i]->ft->clips != 0)
3025       lsx_warn(i < input_count?"`%s' input clipped %" PRIu64 " samples" :
3026                               "`%s' output clipped %" PRIu64 " samples; decrease volume?",
3027           (files[i]->ft->handler.flags & SOX_FILE_DEVICE)?
3028                        files[i]->ft->handler.names[0] : files[i]->ft->filename,
3029           files[i]->ft->clips);
3030 
3031   if (mixing_clips > 0)
3032     lsx_warn("mix-combining clipped %" PRIu64 " samples; decrease volume?", mixing_clips);
3033 
3034   for (i = 0; i < file_count; i++)
3035     if (files[i]->volume_clips > 0)
3036       lsx_warn("`%s' balancing clipped %" PRIu64 " samples; decrease volume?",
3037           files[i]->filename, files[i]->volume_clips);
3038 
3039   if (show_progress) {
3040     if (user_abort)
3041       fprintf(stderr, "Aborted.\n");
3042     else if (user_skip && sox_mode != sox_rec)
3043       fprintf(stderr, "Skipped.\n");
3044     else
3045       fprintf(stderr, "Done.\n");
3046   }
3047 
3048   success = 1; /* Signal success to cleanup so the output file isn't removed. */
3049 
3050   cleanup();
3051 
3052   return 0;
3053 }
3054