/* 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. Load more
/* 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 8 static 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;