Sigrid Solveig Haflínudóttirfix warnings6bc6a9b3 years agoHistory
3038 lines · 99.6 KB · C
RawDownload
/* SoX - The Swiss Army Knife of Audio Manipulation. * * This is the main function for the SoX command line programs: *   sox, play, rec, soxi. * * Copyright 1998-2009 Chris Bagwell and SoX contributors * Copyright 1991 Lance Norskog And Sundry Contributors * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "soxconfig.h"#include "sox.h"#include "util.h" #include <ctype.h>#include <errno.h>#include <fcntl.h>#include <math.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <time.h> #if defined(HAVE_GLOB_H)  #include <glob.h>#endif #ifdef HAVE_IO_H  #include <io.h>#endif #ifdef HAVE_SYS_TIME_H  #include <sys/time.h>#endif #ifdef HAVE_SYS_TIMEB_H  #include <sys/timeb.h>#endif #ifdef HAVE_SYS_UTSNAME_H  #include <sys/utsname.h>#endif #ifdef HAVE_UNISTD_H  #include <unistd.h>#endif #ifdef HAVE_SYS_IOCTL_H  #include <sys/ioctl.h>#endif #ifdef HAVE_GETTIMEOFDAY  #define TIME_FRAC 1e6#else  #define timeval timeb  #define gettimeofday(a,b) ftime(a)  #define tv_sec time  #define tv_usec millitm  #define TIME_FRAC 1e3#endif #if !defined(HAVE_CONIO_H) && !defined(HAVE_TERMIOS_H) && (defined(_MSC_VER) || defined(__MINGW32__))#define HAVE_CONIO_H 1#endif #ifdef HAVE_CONIO_H/* _kbhit and _getch */#include <conio.h>#undef HAVE_TERMIOS_H#endif /*#define MORE_INTERACTIVE 1*/ #define SOX_OPTS "SOX_OPTS"static lsx_getopt_t optstate; /* argv[0] options */ static char const * myname = NULL;static enum {sox_sox, sox_play, sox_rec, sox_soxi} sox_mode;  /* gopts */ static enum {  sox_sequence, sox_concatenate, sox_mix, sox_mix_power,  sox_merge, sox_multiply, sox_default} combine_method = sox_default;static enum { sox_single, sox_multiple } output_method = sox_single;#define is_serial(m) ((m) <= sox_concatenate)#define is_parallel(m) (!is_serial(m))static sox_bool no_clobber = sox_false, interactive = sox_false;static sox_bool uservolume = sox_false;typedef enum {RG_off, RG_track, RG_album, RG_default} rg_mode;static lsx_enum_item const rg_modes[] = {  LSX_ENUM_ITEM(RG_,off)  LSX_ENUM_ITEM(RG_,track)  LSX_ENUM_ITEM(RG_,album)  {0, 0}};static rg_mode replay_gain_mode = RG_default;static sox_option_t show_progress = sox_option_default;  /* Input & output files */ typedef struct {  char * filename;   /* fopts */  char const * filetype;  sox_signalinfo_t signal;  sox_encodinginfo_t encoding;  double volume;  double replay_gain;  sox_oob_t oob;  sox_bool no_glob;   sox_format_t * ft;  /* libSoX file descriptor */  uint64_t volume_clips;  rg_mode replay_gain_mode;} file_t; static file_t * * files = NULL; /* Array tracking input and output files */#define ofile files[file_count - 1]static size_t file_count = 0;static size_t input_count = 0;static size_t output_count = 0; /* Effects */ /* We parse effects into a temporary effects table and then place into * the real effects chain.  This allows scanning all effects to give * hints to what input effect options should be as well as determining * when mixer or resample effects need to be auto-inserted as well. */static sox_effect_t **user_efftab = NULL;static size_t user_efftab_size = 0;static sox_effects_chain_t *effects_chain = NULL;static sox_effect_t *save_output_eff = NULL; static struct { char *name; int argc; char **argv; size_t argv_size; } **user_effargs = NULL;static size_t *user_effargs_size = NULL;  /* array: size of user_effargs for each chain *//* Size of memory structures related to effects arguments (user_effargs[i], * user_effargs[i][j].argv) to be extended in steps of EFFARGS_STEP */#define EFFARGS_STEP 8static size_t *nuser_effects = NULL;  /* array: number of effects in each chain */static size_t current_eff_chain = 0;static size_t eff_chain_count = 0;static sox_bool very_first_effchain = sox_true;  /* Indicates that not only the first effects chain is in effect (hrm), but     also that it has never been restarted. Only then we may use the     optimize_trim() hack. */static char *effects_filename = NULL;static char * play_rate_arg = NULL;static char *norm_level = NULL; /* Flowing */ static sox_signalinfo_t combiner_signal, ofile_signal_options;static sox_encodinginfo_t combiner_encoding, ofile_encoding_options;static uint64_t mixing_clips = 0;static size_t current_input = 0;static uint64_t input_wide_samples = 0;static uint64_t read_wide_samples = 0;static uint64_t output_samples = 0;static sox_bool input_eof = sox_false;static sox_bool output_eof = sox_false;static sox_bool user_abort = sox_false;static sox_bool user_skip = sox_false;static sox_bool user_restart_eff = sox_false;static int success = 0;static int cleanup_called = 0;static sox_sample_t omax[2], omin[2]; #ifdef HAVE_TERMIOS_H#include <termios.h>static struct termios original_termios;static sox_bool original_termios_saved = sox_false;#endif static sox_bool stdin_is_a_tty, is_player, is_guarded, do_guarded_norm, no_dither, reported_sox_opts; struct timeval load_timeofday; static void cleanup(void){  size_t i;   if (!success && !reported_sox_opts) {    char const * env_opts = getenv(SOX_OPTS);    if (env_opts && *env_opts)      lsx_report("used "SOX_OPTS"=%s", env_opts);  }  /* Close the input and output files before exiting. */  for (i = 0; i < input_count; i++) {    if (files[i]->ft) {      sox_close(files[i]->ft);    }    free(files[i]->filename);    free(files[i]);  }   if (file_count) {    if (ofile->ft) {      if (!success && ofile->ft->io_type == lsx_io_file) {   /* If we failed part way through */        struct stat st;                  /* writing a normal file, remove it. */        if (!stat(ofile->ft->filename, &st) &&            (st.st_mode & S_IFMT) == S_IFREG)          unlink(ofile->ft->filename);      }      sox_close(ofile->ft); /* Assume we can unlink a file before closing it. */    }    free(ofile->filename);    free(ofile);  }   free(files); #ifdef HAVE_TERMIOS_H  if (original_termios_saved)    tcsetattr(fileno(stdin), TCSANOW, &original_termios);#endif   free(user_efftab);   free(sox_globals.tmp_path);  sox_globals.tmp_path = NULL;   free(play_rate_arg);  free(effects_filename);  free(norm_level);   sox_quit();   cleanup_called = 1;} /* Cleanup atexit() function, hence always called. */static void atexit_cleanup(void){  /* Do not call cleanup using atexit() if possible.  pthread's can   * act unpredictable if called outside of main().   */  if (!cleanup_called)    cleanup();} static char const * str_time(double seconds){  static char string[16][50];  static int i;  int hours, mins = seconds / 60;  seconds -= mins * 60;  hours = mins / 60;  mins -= hours * 60;  i = (i+1) & 15;  sprintf(string[i], "%02i:%02i:%05.2f", hours, mins, seconds);  return string[i];} static char const * size_and_bitrate(sox_format_t * ft, char const * * text){  off_t size = lsx_filelength(ft);  if (ft->signal.length && ft->signal.channels && ft->signal.rate && text) {    double secs = ft->signal.length / ft->signal.channels / ft->signal.rate;    *text = lsx_sigfigs3(8. * size / secs);  }  return lsx_sigfigs3((double)size);} static void play_file_info(sox_format_t * ft, file_t * f, sox_bool full){  FILE * const output = sox_mode == sox_soxi? stdout : stderr;  char const * text, * text2 = NULL;  char buffer[30];  uint64_t ws = ft->signal.length / ft->signal.channels;  (void)full;   fprintf(output, "\n");  if (ft->filename[0]) {    fprintf(output, "%s:", ft->filename);    if (strcmp(ft->filename, "-") == 0 || (ft->handler.flags & SOX_FILE_DEVICE))      fprintf(output, " (%s)", ft->handler.names[0]);    fprintf(output, "\n\n");  }   if ((text = size_and_bitrate(ft, &text2))) {    fprintf(output, " File Size: %-10s", text);    if (text2)      fprintf(output, "Bit Rate: %s", text2);    fprintf(output, "\n");  }   fprintf(output, "  Encoding: %-14s", sox_encodings_info[ft->encoding.encoding].name);  text = sox_find_comment(f->ft->oob.comments, "Comment");  if (!text)    text = sox_find_comment(f->ft->oob.comments, "Description");  if (!text)    text = sox_find_comment(f->ft->oob.comments, "Year");  if (text)    fprintf(output, "Info: %s", text);  fprintf(output, "\n");   sprintf(buffer, "  Channels: %u @ %u-bit", ft->signal.channels, ft->signal.precision);  fprintf(output, "%-25s", buffer);  text = sox_find_comment(f->ft->oob.comments, "Tracknumber");  if (text) {    fprintf(output, "Track: %s", text);    text = sox_find_comment(f->ft->oob.comments, "Tracktotal");    if (text)      fprintf(output, " of %s", text);  }  fprintf(output, "\n");   sprintf(buffer, "Samplerate: %gHz", ft->signal.rate);  fprintf(output, "%-25s", buffer);  text = sox_find_comment(f->ft->oob.comments, "Album");  if (text)    fprintf(output, "Album: %s", text);  fprintf(output, "\n");   if (f && f->replay_gain != HUGE_VAL){    sprintf(buffer, "%s gain: %+.1fdB", lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text, f->replay_gain);    buffer[0] += 'A' - 'a';    fprintf(output, "%-24s", buffer);  } else    fprintf(output, "%-24s", "Replaygain: off");  text = sox_find_comment(f->ft->oob.comments, "Artist");  if (text)    fprintf(output, "Artist: %s", text);  fprintf(output, "\n");   fprintf(output, "  Duration: %-13s", ft->signal.length? str_time((double)ws / ft->signal.rate) : "unknown");  text = sox_find_comment(f->ft->oob.comments, "Title");  if (text)    fprintf(output, "Title: %s", text);  fprintf(output, "\n\n");} static void display_file_info(sox_format_t * ft, file_t * f, sox_bool full){  static char const * const no_yes[] = {"no", "yes"};  FILE * const output = sox_mode == sox_soxi? stdout : stderr;  char const * filetype = lsx_find_file_extension(ft->filename);  sox_bool show_type = sox_true;  size_t i;   if (is_player && sox_globals.verbosity < 3) {    play_file_info(ft, f, full);    return;  }   fprintf(output, "\n%s: '%s'",    ft->mode == 'r'? "Input File     " : "Output File    ", ft->filename);  if (filetype) for (i = 0; ft->handler.names[i] && show_type; ++i)    if (!strcasecmp(filetype, ft->handler.names[i]))      show_type = sox_false;  if (show_type)    fprintf(output, " (%s)", ft->handler.names[0]);  fprintf(output, "\n");   fprintf(output,    "Channels       : %u\n"    "Sample Rate    : %g\n"    "Precision      : %u-bit\n",    ft->signal.channels,    ft->signal.rate,    ft->signal.precision);   if (ft->signal.length && ft->signal.channels && ft->signal.rate) {    uint64_t ws = ft->signal.length / ft->signal.channels;    char const * text, * text2 = NULL;    fprintf(output,        "Duration       : %s = %" PRIu64 " samples %c %g CDDA sectors\n",        str_time((double)ws / ft->signal.rate),        ws, "~="[ft->signal.rate == 44100],        (double)ws / ft->signal.rate * 44100 / 588);    if (ft->mode == 'r' && (text = size_and_bitrate(ft, &text2))) {      fprintf(output, "File Size      : %s\n", text);      if (text2)        fprintf(output, "Bit Rate       : %s\n", text2);    }  }   if (ft->encoding.encoding) {    char buffer[20] = {'\0'};    if (ft->encoding.bits_per_sample)      sprintf(buffer, "%u-bit ", ft->encoding.bits_per_sample);     fprintf(output, "Sample Encoding: %s%s\n", buffer,        sox_encodings_info[ft->encoding.encoding].desc);  }   if (full) {    if (ft->encoding.bits_per_sample > 8 || (ft->handler.flags & SOX_FILE_ENDIAN))      fprintf(output, "Endian Type    : %s\n",          ft->encoding.reverse_bytes != MACHINE_IS_BIGENDIAN ? "big" : "little");    if (ft->encoding.bits_per_sample)      fprintf(output,        "Reverse Nibbles: %s\n"        "Reverse Bits   : %s\n",        no_yes[ft->encoding.reverse_nibbles],        no_yes[ft->encoding.reverse_bits]);  }   if (f && f->replay_gain != HUGE_VAL)    fprintf(output, "Replay gain    : %+g dB (%s)\n" , f->replay_gain,        lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text);  if (f && f->volume != HUGE_VAL)    fprintf(output, "Level adjust   : %g (linear gain)\n" , f->volume);   if (!(ft->handler.flags & SOX_FILE_DEVICE) && ft->oob.comments) {    if (sox_num_comments(ft->oob.comments) > 1) {      sox_comments_t p = ft->oob.comments;      fprintf(output, "Comments       : \n");      do fprintf(output, "%s\n", *p);      while (*++p);    }    else fprintf(output, "Comment        : '%s'\n", ft->oob.comments[0]);  }  fprintf(output, "\n");} static void report_file_info(file_t * f){  if (sox_globals.verbosity > 2)    display_file_info(f->ft, f, sox_true);} static void progress_to_next_input_file(file_t * f, sox_effect_t * effp){  if (user_skip) {    user_skip = sox_false;    fprintf(stderr, "\nSkipped (Ctrl-C twice to quit).\n");  }  read_wide_samples = 0;  input_wide_samples = f->ft->signal.length / f->ft->signal.channels;  if (show_progress && (sox_globals.verbosity < 3 ||                        (is_serial(combine_method) && input_count > 1)))    display_file_info(f->ft, f, sox_false);  if (f->volume == HUGE_VAL)    f->volume = 1;  if (f->replay_gain != HUGE_VAL)    f->volume *= pow(10.0, f->replay_gain / 20);  if (effp && f->volume != floor(f->volume))    effp->out_signal.precision = SOX_SAMPLE_PRECISION;  f->ft->sox_errno = errno = 0;} /* Read up to max `wide' samples.  A wide sample contains one sample per channel * from the input audio. */static size_t sox_read_wide(sox_format_t * ft, sox_sample_t * buf, size_t max){  size_t len = max / combiner_signal.channels;  len = sox_read(ft, buf, len * ft->signal.channels) / ft->signal.channels;  if (!len && ft->sox_errno)    lsx_fail("`%s' %s: %s",        ft->filename, ft->sox_errstr, sox_strerror(ft->sox_errno));  return len;} static void balance_input(sox_sample_t * buf, size_t ws, file_t * f){  size_t s = ws * f->ft->signal.channels;   if (f->volume != 1) while (s--) {    double d = f->volume * *buf;    *buf++ = SOX_ROUND_CLIP_COUNT(d, f->volume_clips);  }} /* The input combiner: contains one sample buffer per input file, but only * needed if is_parallel(combine_method) */typedef struct {  sox_sample_t * * ibuf;  size_t *         ilen;} input_combiner_t; static int combiner_start(sox_effect_t *effp){  input_combiner_t * z = (input_combiner_t *) effp->priv;  uint64_t ws;  size_t i; 

Lines 1–500 of 3038.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t