📄 sox.c
字号:
/* * Sox - The Swiss Army Knife of Audio Manipulation. * * This is the main function for the command line sox program. * * July 5, 1991 * Copyright 1991 Lance Norskog And Sundry Contributors * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Lance Norskog And Sundry Contributors are not responsible for * the consequences of using this software. * * Change History: * * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com) * Added patch to get volume working again. Based on patch sent from * Matija Nalis <mnalis@public.srce.hr>. * Added command line switches to force format to ADPCM or GSM. * * September 12, 1998 - Chris Bagwell (cbagwell@sprynet.com) * Reworked code that handled effects. Wasn't correctly draining * stereo effects and a few other problems. * Made command usage (-h) show supported effects and file formats. * (this is partially from a patch by Leigh Smith * leigh@psychokiller.dialix.oz.au). * */ #include "st.h"#include "version.h"#include "patchlvl.h"#include <stdio.h>#include <string.h>#if defined(unix) || defined(AMIGA) || defined(__OS2__)#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#ifdef HAS_GETOPT_H#include <getopt.h>#endif#endif#if defined(__STDC__)#include <stdarg.h>#else#include <varargs.h>#endif#include <ctype.h>#ifdef VMS#include <errno.h>#include <perror.h>#define LASTCHAR ']'#else#include <errno.h>#define LASTCHAR '/'#endif/* * SOX main program. * * Rewrite for new nicer option syntax. July 13, 1991. * Rewrite for separate effects library. Sep. 15, 1991. * Incorporate Jimen Ching's fixes for real library operation: Aug 3, 1994. * Rewrite for multiple effects: Aug 24, 1994. */#ifdef AMIGA/* This is the Amiga version string */char amiversion[AmiVerSize]=AmiVerChars; #endif /* AMIGA */#ifdef DOSextern char writebuf[BUFSIZ];#endifint clipped = 0; /* Volume change clipping errors */static LONG ibufl[BUFSIZ/2]; /* Left/right interleave buffers */static LONG ibufr[BUFSIZ/2]; static LONG obufl[BUFSIZ/2];static LONG obufr[BUFSIZ/2];void init();void doopts(P2(int, char **));void usage(P1(char *));int filetype(P1(int));void process();void statistics();LONG volumechange();void checkeffect(P1(eff_t));#ifdef NEED_GETOPTint getopt(P3(int,char **,char *));#endifint flow_effect(P1(int));int drain_effect(P1(int));struct soundstream informat, outformat;ft_t ft;#define MAXEFF 4struct effect eff;struct effect efftab[MAXEFF]; /* table of left/mono channel effects */struct effect efftabR[MAXEFF]; /* table of right channel effects */ /* efftab[0] is the input stream */int neffects; /* # of effects */char *ifile, *ofile, *itype, *otype;IMPORT char *optarg;IMPORT int optind;int main(argc, argv)int argc;char **argv;{ myname = argv[0]; init(); ifile = ofile = NULL; /* Get input format options */ ft = &informat; doopts(argc, argv); /* Get input file */ if (optind >= argc) usage("No input file?"); ifile = argv[optind]; if (! strcmp(ifile, "-")) ft->fp = stdin; else if ((ft->fp = fopen(ifile, READBINARY)) == NULL) fail("Can't open input file '%s': %s", ifile, strerror(errno)); ft->filename = ifile; optind++; /* If more arguments are left then look for -e to see if */ /* no output file is used, then just do an effect */ if (optind < argc && strcmp(argv[optind], "-e")) writing = 1; else if (optind < argc) { writing = 0; optind++; /* Move passed -e */ } else writing = 1; /* No arguments left but let next check fail */ /* Get output format options */ ft = &outformat; doopts(argc, argv); if (writing) { /* Get output file */ if (optind >= argc) usage("No output file?"); ofile = argv[optind]; ft->filename = ofile; /* * There are two choices here: * 1) stomp the old file - normal shell "> file" behavior * 2) fail if the old file already exists - csh mode */ if (! strcmp(ofile, "-")) ft->fp = stdout; else {#ifdef unix /* * Remove old file if it's a text file, but * preserve Unix /dev/sound files. */ if ((ft->fp = fopen(ofile, WRITEBINARY)) && (filetype(fileno(ft->fp)) == S_IFREG)) { fclose(ft->fp); unlink(ofile); creat(ofile, 0666); ft->fp = fopen(ofile, WRITEBINARY); }#else ft->fp = fopen(ofile, WRITEBINARY);#endif if (ft->fp == NULL) fail("Can't open output file '%s': %s", ofile, strerror(errno));#ifdef DOS if (setvbuf (ft->fp,writebuf,_IOFBF,sizeof(char)*BUFSIZ)) fail("Can't set write buffer");#endif } /* end of else != stdout */ /* Move passed filename */ optind++; } /* end if writing */ /* Get effect name */ if (optind < argc) { eff.name = argv[optind]; optind++; geteffect(&eff); (* eff.h->getopts)(&eff, argc - optind, &argv[optind]); } else { eff.name = "null"; geteffect(&eff); } /* Check global arguments */ if (volume <= 0.0) fail("Volume must be greater than 0.0"); #if defined(unix) || defined(AMIGA) informat.seekable = (filetype(fileno(informat.fp)) == S_IFREG); outformat.seekable = (filetype(fileno(outformat.fp)) == S_IFREG); #else#if defined(DOS) || defined(__OS2__) informat.seekable = 1; outformat.seekable = 1;#else informat.seekable = 0; outformat.seekable = 0;#endif#endif /* If file types have not been set with -t, set from file names. */ if (! informat.filetype) { if ((informat.filetype = strrchr(ifile, LASTCHAR)) != NULL) informat.filetype++; else informat.filetype = ifile; if ((informat.filetype = strrchr(informat.filetype, '.')) != NULL) informat.filetype++; else /* Default to "auto" */ informat.filetype = "auto"; } if (writing && ! outformat.filetype) { if ((outformat.filetype = strrchr(ofile, LASTCHAR)) != NULL) outformat.filetype++; else outformat.filetype = ofile; if ((outformat.filetype = strrchr(outformat.filetype, '.')) != NULL) outformat.filetype++; } /* Default the input comment to the filename. * The output comment will be assigned when the informat * structure is copied to the outformat. */ informat.comment = informat.filename; process(); statistics(); return(0);}#ifdef HAS_GETOPT_Hchar *getoptstr = "+r:v:t:c:phsuUAagbwlfdDxV";#elsechar *getoptstr = "r:v:t:c:phsuUAagbwlfdDxV";#endifvoid doopts(argc, argv)int argc;char **argv;{ int c; char *str; while ((c = getopt(argc, argv, getoptstr)) != -1) { switch(c) { case 'p': soxpreview++; break; case 'h': usage((char *)0); /* no return from above */ case 't': if (! ft) usage("-t"); ft->filetype = optarg; if (ft->filetype[0] == '.') ft->filetype++; break; case 'r': if (! ft) usage("-r"); str = optarg;#ifdef __alpha__ if ((! sscanf(str, "%u", &ft->info.rate)) || (ft->info.rate <= 0))#else if ((! sscanf(str, "%lu", &ft->info.rate)) || (ft->info.rate <= 0))#endif fail("-r must be given a positive integer"); break; case 'v': if (! ft) usage("-v"); str = optarg; if ((! sscanf(str, "%e", &volume)) || (volume <= 0)) fail("Volume value '%s' is not a number", optarg); dovolume = 1; break; case 'c': if (! ft) usage("-c"); str = optarg; if (! sscanf(str, "%d", &ft->info.channels)) fail("-c must be given a number"); break; case 'b': if (! ft) usage("-b"); ft->info.size = BYTE; break; case 'w': if (! ft) usage("-w"); ft->info.size = WORD; break; case 'l': if (! ft) usage("-l"); ft->info.size = DWORD; break; case 'f': if (! ft) usage("-f"); ft->info.size = FLOAT; break; case 'd': if (! ft) usage("-d"); ft->info.size = DOUBLE; break; case 'D': if (! ft) usage("-D"); ft->info.size = IEEE; break; case 's': if (! ft) usage("-s"); ft->info.style = SIGN2; break; case 'u': if (! ft) usage("-u"); ft->info.style = UNSIGNED; break; case 'U': if (! ft) usage("-U"); ft->info.style = ULAW; break; case 'A': if (! ft) usage("-A"); ft->info.style = ALAW; break; case 'a': if (! ft) usage("-a"); ft->info.style = ADPCM; break; case 'g': if (! ft) usage("-g"); ft->info.style = GSM; break; case 'x': if (! ft) usage("-x"); ft->swap = 1; break; case 'V': verbose = 1; break; } }}void init() { /* init files */ informat.info.rate = outformat.info.rate = 0; informat.info.size = outformat.info.size = -1; informat.info.style = outformat.info.style = -1; informat.info.channels = outformat.info.channels = -1; informat.comment = outformat.comment = NULL; informat.swap = 0; informat.filetype = outformat.filetype = (char *) 0; informat.fp = stdin; outformat.fp = stdout; informat.filename = "input"; outformat.filename = "output";}/* * Process input file -> effect table -> output file * one buffer at a time */void process() { LONG i; int e, f, havedata; gettype(&informat); if (writing) gettype(&outformat); /* Read and write starters can change their formats. */ (* informat.h->startread)(&informat); checkformat(&informat); if (dovolume) report("Volume factor: %f\n", volume); report("Input file: using sample rate %lu\n\tsize %s, style %s, %d %s", informat.info.rate, sizes[informat.info.size], styles[informat.info.style], informat.info.channels, (informat.info.channels > 1) ? "channels" : "channel"); if (informat.comment) report("Input file: comment \"%s\"\n", informat.comment); /* need to check EFF_REPORT */ if (writing) { copyformat(&informat, &outformat); (* outformat.h->startwrite)(&outformat); checkformat(&outformat); cmpformats(&informat, &outformat); report("Output file: using sample rate %lu\n\tsize %s, style %s, %d %s", outformat.info.rate, sizes[outformat.info.size], styles[outformat.info.style], outformat.info.channels, (outformat.info.channels > 1) ? "channels" : "channel"); if (outformat.comment) report("Output file: comment \"%s\"\n", outformat.comment); } /* Very Important: * Effect fabrication and start is called AFTER files open. * Effect may write out data beforehand, and * some formats don't know their sample rate until now. */ /* inform effect about signal information */ eff.ininfo = informat.info; eff.outinfo = outformat.info; for(i = 0; i < 8; i++) { memcpy(&eff.loops[i], &informat.loops[i], sizeof(struct loopinfo)); } eff.instr = informat.instr; /* build efftab */ checkeffect(&eff); /* Start all effects */ for(e = 1; e < neffects; e++) { (* efftab[e].h->start)(&efftab[e]); if (efftabR[e].name) (* efftabR[e].h->start)(&efftabR[e]); } /* Reserve an output buffer for all effects */ for(e = 0; e < neffects; e++) { efftab[e].obuf = (LONG *) malloc(BUFSIZ * sizeof(LONG)); if (efftabR[e].name) efftabR[e].obuf = (LONG *) malloc(BUFSIZ * sizeof(LONG)); } /* Read initial chunk of input data. */ efftab[0].olen = (*informat.h->read)(&informat, efftab[0].obuf, (LONG) BUFSIZ); efftab[0].odone = 0; /* Change the volume of this initial input data if needed. */ if (dovolume)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -