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