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