home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / SoX / Source / sox.c < prev    next >
C/C++ Source or Header  |  1999-09-16  |  24KB  |  907 lines

  1. /*
  2.  * Sox - The Swiss Army Knife of Audio Manipulation.
  3.  *
  4.  * This is the main function for the command line sox program.
  5.  *
  6.  * July 5, 1991
  7.  * Copyright 1991 Lance Norskog And Sundry Contributors
  8.  * This source code is freely redistributable and may be used for
  9.  * any purpose.  This copyright notice must be maintained. 
  10.  * Lance Norskog And Sundry Contributors are not responsible for 
  11.  * the consequences of using this software.
  12.  *
  13.  * Change History:
  14.  *
  15.  * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com)
  16.  *   Added patch to get volume working again.  Based on patch sent from
  17.  *   Matija Nalis <mnalis@public.srce.hr>.
  18.  *   Added command line switches to force format to ADPCM or GSM.
  19.  *
  20.  * September 12, 1998 - Chris Bagwell (cbagwell@sprynet.com)
  21.  *   Reworked code that handled effects.  Wasn't correctly draining
  22.  *   stereo effects and a few other problems.
  23.  *   Made command usage (-h) show supported effects and file formats.
  24.  *   (this is partially from a patch by Leigh Smith
  25.  *    leigh@psychokiller.dialix.oz.au).
  26.  *
  27.  */ 
  28.  
  29. #include "st.h"
  30. #include "version.h"
  31. #include "patchlvl.h"
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <stdlib.h>        /* for malloc() */
  35. #ifdef HAVE_MALLOC_H
  36. #include <malloc.h>
  37. #endif
  38. #include <errno.h>
  39. #include <sys/types.h>        /* for fstat() */
  40. #include <sys/stat.h>        /* for fstat() */
  41.  
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>        /* for unlink() */
  44. #endif
  45.  
  46. #ifdef HAVE_GETOPT_H
  47. #include <getopt.h>
  48. #else
  49. #ifndef HAVE_GETOPT
  50. int getopt(P3(int,char **,char *));
  51. #endif
  52. #endif
  53.  
  54. #ifdef VMS
  55. #include <perror.h>
  56. #define LASTCHAR        ']'
  57. #else
  58. #define LASTCHAR        '/'
  59. #endif
  60.  
  61. /*
  62.  * SOX main program.
  63.  *
  64.  * Rewrite for new nicer option syntax.  July 13, 1991.
  65.  * Rewrite for separate effects library.  Sep. 15, 1991.
  66.  * Incorporate Jimen Ching's fixes for real library operation: Aug 3, 1994.
  67.  * Rewrite for multiple effects: Aug 24, 1994.
  68.  */
  69.  
  70. int clipped = 0;        /* Volume change clipping errors */
  71.  
  72. static LONG ibufl[BUFSIZ/2];    /* Left/right interleave buffers */
  73. static LONG ibufr[BUFSIZ/2];    
  74. static LONG obufl[BUFSIZ/2];
  75. static LONG obufr[BUFSIZ/2];
  76.  
  77. void init();
  78. void doopts(P2(int, char **));
  79. void usage(P1(char *));
  80. int filetype(P1(int));
  81. void process();
  82. void statistics();
  83. LONG volumechange();
  84. void checkeffect(P1(eff_t));
  85. int flow_effect(P1(int));
  86. int drain_effect(P1(int));
  87.  
  88. struct soundstream informat, outformat;
  89.  
  90. ft_t ft;
  91.  
  92. #define MAXEFF 4
  93. struct effect eff;
  94. struct effect efftab[MAXEFF];    /* table of left/mono channel effects */
  95. struct effect efftabR[MAXEFF];    /* table of right channel effects */
  96.                 /* efftab[0] is the input stream */
  97. int neffects;            /* # of effects */
  98. char *ifile, *ofile, *itype, *otype;
  99. IMPORT char *optarg;
  100. IMPORT int optind;
  101.  
  102. int main(argc, argv)
  103. int argc;
  104. char **argv;
  105. {
  106.     myname = argv[0];
  107.     init();
  108.     
  109.     ifile = ofile = NULL;
  110.  
  111.     /* Get input format options */
  112.     ft = &informat;
  113.     doopts(argc, argv);
  114.     /* Get input file */
  115.     if (optind >= argc)
  116.         usage("No input file?");
  117.     
  118.     ifile = argv[optind];
  119.     if (! strcmp(ifile, "-"))
  120.         ft->fp = stdin;
  121.     else if ((ft->fp = fopen(ifile, READBINARY)) == NULL)
  122.         fail("Can't open input file '%s': %s", 
  123.             ifile, strerror(errno));
  124.     ft->filename = ifile;
  125.     optind++;
  126.  
  127.     /* If more arguments are left then look for -e to see if */
  128.     /* no output file is used, then just do an effect */
  129.     if (optind < argc && strcmp(argv[optind], "-e"))
  130.         writing = 1;
  131.     else if (optind < argc) {
  132.         writing = 0;
  133.         optind++;  /* Move passed -e */
  134.     }
  135.     else
  136.         writing = 1;  /* No arguments left but let next check fail */
  137.         
  138.     /* Get output format options */
  139.     ft = &outformat;
  140.     doopts(argc, argv);
  141.  
  142.     if (writing) {
  143.         /* Get output file */
  144.         if (optind >= argc)
  145.         usage("No output file?");
  146.         ofile = argv[optind];
  147.         ft->filename = ofile;
  148.         /*
  149.          * There are two choices here:
  150.          *    1) stomp the old file - normal shell "> file" behavior
  151.          *    2) fail if the old file already exists - csh mode
  152.          */
  153.         if (! strcmp(ofile, "-"))
  154.         {
  155.         ft->fp = stdout;
  156.  
  157.         /* stdout tends to be line-buffered.  Override this */
  158.         /* to be Full Buffering. */
  159.         if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
  160.             fail("Can't set write buffer");
  161.         }
  162.         else {
  163.  
  164.         ft->fp = fopen(ofile, WRITEBINARY);
  165.  
  166.         if (ft->fp == NULL)
  167.             fail("Can't open output file '%s': %s", 
  168.              ofile, strerror(errno));
  169.  
  170.         /* stdout tends to be line-buffered.  Override this */
  171.         /* to be Full Buffering. */
  172.         if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
  173.             fail("Can't set write buffer");
  174.  
  175.         } /* end of else != stdout */
  176.         
  177.         /* Move passed filename */
  178.         optind++;
  179.     } /* end if writing */
  180.  
  181.     /* Get effect name */
  182.     if (optind < argc) {
  183.         eff.name = argv[optind];
  184.         optind++;
  185.         geteffect(&eff);
  186.         (* eff.h->getopts)(&eff, argc - optind, &argv[optind]);
  187.     } else {
  188.         eff.name = "null";
  189.         geteffect(&eff);
  190.     }
  191.  
  192.     /* Check global arguments */
  193.     if (volume <= 0.0)
  194.         fail("Volume must be greater than 0.0");
  195.     
  196. #if    defined(DUMB_FILESYSETM)
  197.     informat.seekable  = 0;
  198.     outformat.seekable = 0;
  199. #else
  200.     informat.seekable  = (filetype(fileno(informat.fp)) == S_IFREG);
  201.     outformat.seekable = (filetype(fileno(outformat.fp)) == S_IFREG); 
  202. #endif
  203.  
  204.     /* If file types have not been set with -t, set from file names. */
  205.     if (! informat.filetype) {
  206.         if ((informat.filetype = strrchr(ifile, LASTCHAR)) != NULL)
  207.             informat.filetype++;
  208.         else
  209.             informat.filetype = ifile;
  210.         if ((informat.filetype = strrchr(informat.filetype, '.')) != NULL)
  211.             informat.filetype++;
  212.         else /* Default to "auto" */
  213.             informat.filetype = "auto";
  214.     }
  215.     if (writing && ! outformat.filetype) {
  216.         if ((outformat.filetype = strrchr(ofile, LASTCHAR)) != NULL)
  217.             outformat.filetype++;
  218.         else
  219.             outformat.filetype = ofile;
  220.         if ((outformat.filetype = strrchr(outformat.filetype, '.')) != NULL)
  221.             outformat.filetype++;
  222.     }
  223.     /* Default the input comment to the filename. 
  224.      * The output comment will be assigned when the informat 
  225.      * structure is copied to the outformat. 
  226.      */
  227.     informat.comment = informat.filename;
  228.  
  229.     process();
  230.     statistics();
  231.     return(0);
  232. }
  233.  
  234. #ifdef HAVE_GETOPT_H
  235. char *getoptstr = "+r:v:t:c:phsuUAagbwlfdDxV";
  236. #else
  237. char *getoptstr = "r:v:t:c:phsuUAagbwlfdDxV";
  238. #endif
  239.  
  240. void doopts(argc, argv)
  241. int argc;
  242. char **argv;
  243. {
  244.     int c;
  245.     char *str;
  246.  
  247.     while ((c = getopt(argc, argv, getoptstr)) != -1) {
  248.         switch(c) {
  249.         case 'p':
  250.             soxpreview++;
  251.             break;
  252.  
  253.         case 'h':
  254.             usage((char *)0);
  255.             /* no return from above */
  256.  
  257.         case 't':
  258.             if (! ft) usage("-t");
  259.             ft->filetype = optarg;
  260.             if (ft->filetype[0] == '.')
  261.                 ft->filetype++;
  262.             break;
  263.  
  264.         case 'r':
  265.             if (! ft) usage("-r");
  266.             str = optarg;
  267. #ifdef __alpha__
  268.             if ((! sscanf(str, "%u", &ft->info.rate)) ||
  269.                     (ft->info.rate <= 0))
  270. #else
  271.             if ((! sscanf(str, "%lu", &ft->info.rate)) ||
  272.                     (ft->info.rate <= 0))
  273. #endif
  274.                 fail("-r must be given a positive integer");
  275.             break;
  276.         case 'v':
  277.             if (! ft) usage("-v");
  278.             str = optarg;
  279.             if ((! sscanf(str, "%e", &volume)) ||
  280.                     (volume <= 0))
  281.                 fail("Volume value '%s' is not a number",
  282.                     optarg);
  283.             dovolume = 1;
  284.             break;
  285.  
  286.         case 'c':
  287.             if (! ft) usage("-c");
  288.             str = optarg;
  289.             if (! sscanf(str, "%d", &ft->info.channels))
  290.                 fail("-c must be given a number");
  291.             break;
  292.         case 'b':
  293.             if (! ft) usage("-b");
  294.             ft->info.size = BYTE;
  295.             break;
  296.         case 'w':
  297.             if (! ft) usage("-w");
  298.             ft->info.size = WORD;
  299.             break;
  300.         case 'l':
  301.             if (! ft) usage("-l");
  302.             ft->info.size = DWORD;
  303.             break;
  304.         case 'f':
  305.             if (! ft) usage("-f");
  306.             ft->info.size = FLOAT;
  307.             break;
  308.         case 'd':
  309.             if (! ft) usage("-d");
  310.             ft->info.size = DOUBLE;
  311.             break;
  312.         case 'D':
  313.             if (! ft) usage("-D");
  314.             ft->info.size = IEEE;
  315.             break;
  316.  
  317.         case 's':
  318.             if (! ft) usage("-s");
  319.             ft->info.style = SIGN2;
  320.             break;
  321.         case 'u':
  322.             if (! ft) usage("-u");
  323.             ft->info.style = UNSIGNED;
  324.             break;
  325.         case 'U':
  326.             if (! ft) usage("-U");
  327.             ft->info.style = ULAW;
  328.             break;
  329.         case 'A':
  330.             if (! ft) usage("-A");
  331.             ft->info.style = ALAW;
  332.             break;
  333.         case 'a':
  334.             if (! ft) usage("-a");
  335.             ft->info.style = ADPCM;
  336.             break;
  337.         case 'g':
  338.             if (! ft) usage("-g");
  339.             ft->info.style = GSM;
  340.             break;
  341.         
  342.         case 'x':
  343.             if (! ft) usage("-x");
  344.             ft->swap = 1;
  345.             break;
  346.         
  347.         case 'V':
  348.             verbose = 1;
  349.             break;
  350.         }
  351.     }
  352. }
  353.  
  354. void init() {
  355.  
  356.     /* init files */
  357.     informat.info.rate      = outformat.info.rate  = 0;
  358.     informat.info.size      = outformat.info.size  = -1;
  359.     informat.info.style     = outformat.info.style = -1;
  360.     informat.info.channels  = outformat.info.channels = -1;
  361.     informat.comment   = outformat.comment = NULL;
  362.     informat.swap      = 0;
  363.     informat.filetype  = outformat.filetype  = (char *) 0;
  364.     informat.fp        = stdin;
  365.     outformat.fp       = stdout;
  366.     informat.filename  = "input";
  367.     outformat.filename = "output";
  368. }
  369.  
  370. /* 
  371.  * Process input file -> effect table -> output file
  372.  *    one buffer at a time
  373.  */
  374.  
  375. void process() {
  376.     LONG i;
  377.     int e, f, havedata;
  378.  
  379.     gettype(&informat);
  380.     if (writing)
  381.     gettype(&outformat);
  382.     
  383.     /* Read and write starters can change their formats. */
  384.     (* informat.h->startread)(&informat);
  385.     checkformat(&informat);
  386.     
  387.     if (dovolume)
  388.     report("Volume factor: %f\n", volume);
  389.     
  390.     report("Input file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  391.        informat.info.rate, sizes[informat.info.size], 
  392.        styles[informat.info.style], informat.info.channels, 
  393.        (informat.info.channels > 1) ? "channels" : "channel");
  394.     if (informat.comment)
  395.     report("Input file: comment \"%s\"\n", informat.comment);
  396.     
  397.     /* need to check EFF_REPORT */
  398.     if (writing) {
  399.     copyformat(&informat, &outformat);
  400.     (* outformat.h->startwrite)(&outformat);
  401.     checkformat(&outformat);
  402.     cmpformats(&informat, &outformat);
  403.     report("Output file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  404.            outformat.info.rate, sizes[outformat.info.size], 
  405.            styles[outformat.info.style], outformat.info.channels, 
  406.            (outformat.info.channels > 1) ? "channels" : "channel");
  407.     if (outformat.comment)
  408.         report("Output file: comment \"%s\"\n", outformat.comment);
  409.     }
  410.  
  411.     /* Very Important: 
  412.      * Effect fabrication and start is called AFTER files open.
  413.      * Effect may write out data beforehand, and
  414.      * some formats don't know their sample rate until now.
  415.      */
  416.     
  417.     /* inform effect about signal information */
  418.     eff.ininfo = informat.info;
  419.     eff.outinfo = outformat.info;
  420.     for(i = 0; i < 8; i++) {
  421.     memcpy(&eff.loops[i], &informat.loops[i], sizeof(struct loopinfo));
  422.     }
  423.     eff.instr = informat.instr;
  424.  
  425.     /* build efftab */
  426.     checkeffect(&eff);
  427.  
  428.     /* Start all effects */
  429.     for(e = 1; e < neffects; e++) {
  430.     (* efftab[e].h->start)(&efftab[e]);
  431.     if (efftabR[e].name) 
  432.         (* efftabR[e].h->start)(&efftabR[e]);
  433.     }
  434.  
  435.     /* Reserve an output buffer for all effects */
  436.     for(e = 0; e < neffects; e++) {
  437.     efftab[e].obuf = (LONG *) malloc(BUFSIZ * sizeof(LONG));
  438.     if (efftabR[e].name) 
  439.         efftabR[e].obuf = (LONG *) malloc(BUFSIZ * sizeof(LONG));
  440.     }
  441.  
  442.     /* Read initial chunk of input data. */
  443.     efftab[0].olen = (*informat.h->read)(&informat, 
  444.                      efftab[0].obuf, (LONG) BUFSIZ);
  445.     efftab[0].odone = 0;
  446.  
  447.     /* Change the volume of this initial input data if needed. */
  448.     if (dovolume)
  449.     for (i = 0; i < efftab[0].olen; i++)
  450.         efftab[0].obuf[i] = volumechange(efftab[0].obuf[i]);
  451.  
  452.     /* Run input data through effects and get more until olen == 0 */
  453.     while (efftab[0].olen > 0) {
  454.  
  455.     /* mark chain as empty */
  456.     for(e = 1; e < neffects; e++)
  457.         efftab[e].odone = efftab[e].olen = 0;
  458.  
  459.     do {
  460.  
  461.         /* run entire chain BACKWARDS: pull, don't push.*/
  462.         /* this is because buffering system isn't a nice queueing system */
  463.         for(e = neffects - 1; e > 0; e--) 
  464.         if (flow_effect(e))
  465.             break;
  466.  
  467.         /* If outputing and output data was generated then write it */
  468.         if (writing&&(efftab[neffects-1].olen>efftab[neffects-1].odone)) {
  469.         (* outformat.h->write)(&outformat, efftab[neffects-1].obuf, 
  470.                        (LONG) efftab[neffects-1].olen);
  471.             efftab[neffects-1].odone = efftab[neffects-1].olen;
  472.         }
  473.  
  474.         /* if stuff still in pipeline, set up to flow effects again */
  475.         havedata = 0;
  476.         for(e = 0; e < neffects - 1; e++)
  477.         if (efftab[e].odone < efftab[e].olen) {
  478.             havedata = 1;
  479.             break;
  480.         }
  481.     } while (havedata);
  482.  
  483.     /* Read another chunk of input data. */
  484.     efftab[0].olen = (*informat.h->read)(&informat, 
  485.         efftab[0].obuf, (LONG) BUFSIZ);
  486.     efftab[0].odone = 0;
  487.  
  488.     /* Change volume of these samples if needed. */
  489.     if (dovolume)
  490.         for (i = 0; i < efftab[0].olen; i++)
  491.         efftab[0].obuf[i] = volumechange(efftab[0].obuf[i]);
  492.     }
  493.  
  494.     /* Drain the effects out first to last, 
  495.      * pushing residue through subsequent effects */
  496.     /* oh, what a tangled web we weave */
  497.     for(f = 1; f < neffects; f++)
  498.     {
  499.     while (1) {
  500.  
  501.         if (drain_effect(f) == 0)
  502.         break;        /* out of while (1) */
  503.     
  504.         if (writing&&efftab[neffects-1].olen > 0)
  505.         (* outformat.h->write)(&outformat, efftab[neffects-1].obuf,
  506.                        (LONG) efftab[neffects-1].olen);
  507.  
  508.         if (efftab[f].olen != BUFSIZ)
  509.         break;
  510.     }
  511.     }
  512.     
  513.  
  514.     /* Very Important: 
  515.      * Effect stop is called BEFORE files close.
  516.      * Effect may write out more data after. 
  517.      */
  518.     
  519.     for (e = 1; e < neffects; e++) {
  520.     (* efftab[e].h->stop)(&efftab[e]);
  521.     if (efftabR[e].name)
  522.         (* efftabR[e].h->stop)(&efftabR[e]);
  523.     }
  524.  
  525.     (* informat.h->stopread)(&informat);
  526.     fclose(informat.fp);
  527.  
  528.     if (writing)
  529.         (* outformat.h->stopwrite)(&outformat);
  530.     if (writing)
  531.         fclose(outformat.fp);
  532. }
  533.  
  534. int flow_effect(e)
  535. int e;
  536. {
  537.     LONG i, idone, odone, idonel, odonel, idoner, odoner;
  538.     LONG *ibuf, *obuf;
  539.  
  540.     /* I have no input data ? */
  541.     if (efftab[e-1].odone == efftab[e-1].olen)
  542.     return 0;
  543.  
  544.     if (! efftabR[e].name) {
  545.     /* No stereo data, or effect can handle stereo data so
  546.      * run effect over entire buffer.
  547.      */
  548.     idone = efftab[e-1].olen - efftab[e-1].odone;
  549.     odone = BUFSIZ;
  550.     (* efftab[e].h->flow)(&efftab[e], 
  551.                   &efftab[e-1].obuf[efftab[e-1].odone], 
  552.                   efftab[e].obuf, &idone, &odone);
  553.     efftab[e-1].odone += idone;
  554.     efftab[e].odone = 0;
  555.     efftab[e].olen = odone;
  556.     } else {
  557.     
  558.     /* Put stereo data in two seperate buffers and run effect
  559.      * on each of them.
  560.      */
  561.     idone = efftab[e-1].olen - efftab[e-1].odone;
  562.     odone = BUFSIZ;
  563.     ibuf = &efftab[e-1].obuf[efftab[e-1].odone];
  564.     for(i = 0; i < idone; i += 2) {
  565.         ibufl[i/2] = *ibuf++;
  566.         ibufr[i/2] = *ibuf++;
  567.     }
  568.     
  569.     /* left */
  570.     idonel = (idone + 1)/2;        /* odd-length logic */
  571.     odonel = odone/2;
  572.     (* efftab[e].h->flow)(&efftab[e], ibufl, obufl, &idonel, &odonel);
  573.     
  574.     /* right */
  575.     idoner = idone/2;        /* odd-length logic */
  576.     odoner = odone/2;
  577.     (* efftabR[e].h->flow)(&efftabR[e], ibufr, obufr, &idoner, &odoner);
  578.  
  579.     obuf = efftab[e].obuf;
  580.      /* This loop implies left and right effect will always output
  581.       * the same amount of data.
  582.       */
  583.     for(i = 0; i < odoner; i++) {
  584.         *obuf++ = obufl[i];
  585.         *obuf++ = obufr[i];
  586.     }
  587.     efftab[e-1].odone += idonel + idoner;
  588.     efftab[e].odone = 0;
  589.     efftab[e].olen = odonel + odoner;
  590.     } 
  591.     if (idone == 0) 
  592.     fail("Effect took no samples!");
  593.     return 1;
  594. }
  595.  
  596. int drain_effect(e)
  597. int e;
  598. {
  599.     LONG i, olen, olenl, olenr;
  600.     LONG *obuf;
  601.  
  602.     if (! efftabR[e].name) {
  603.     efftab[e].olen = BUFSIZ;
  604.     (* efftab[e].h->drain)(&efftab[e],efftab[e].obuf,
  605.                    &efftab[e].olen);
  606.     }
  607.     else {
  608.     olen = BUFSIZ;
  609.         
  610.     /* left */
  611.     olenl = olen/2;
  612.     (* efftab[e].h->drain)(&efftab[e], obufl, &olenl);
  613.     
  614.     /* right */
  615.     olenr = olen/2;
  616.     (* efftab[e].h->drain)(&efftabR[e], obufr, &olenr);
  617.     
  618.     obuf = efftab[e].obuf;
  619.     /* This loop implies left and right effect will always output
  620.      * the same amount of data.
  621.      */
  622.     for(i = 0; i < olenr; i++) {
  623.         *obuf++ = obufl[i];
  624.         *obuf++ = obufr[i];
  625.     }
  626.     efftab[e].olen = olenl + olenr;
  627.     }
  628.     return(efftab[e].olen);
  629. }
  630.  
  631. #define setin(eff, effname) \
  632.     {eff.name = effname; \
  633.     eff.ininfo.rate = informat.info.rate; \
  634.     eff.ininfo.channels = informat.info.channels; \
  635.     eff.outinfo.rate = informat.info.rate; \
  636.     eff.outinfo.channels = informat.info.channels;}
  637.  
  638. #define setout(eff, effname) \
  639.     {eff.name = effname; \
  640.     eff.ininfo.rate = outformat.info.rate; \
  641.     eff.ininfo.channels = outformat.info.channels; \
  642.     eff.outinfo.rate = outformat.info.rate; \
  643.     eff.outinfo.channels = outformat.info.channels;}
  644.  
  645. /*
  646.  * If no effect given, decide what it should be.
  647.  * Smart ruleset for multiple effects in sequence.
  648.  *     Puts user-specified effect in right place.
  649.  */
  650. void
  651. checkeffect(effp)
  652. eff_t effp;
  653. {
  654.     int i, j;
  655.     int needchan = 0, needrate = 0;
  656.  
  657.     /* if given effect does these, we don't need to add them */
  658.     needrate = (informat.info.rate != outformat.info.rate) &&
  659.         ! (effp->h->flags & EFF_RATE);
  660.     needchan = (informat.info.channels != outformat.info.channels) &&
  661.         ! (effp->h->flags & EFF_MCHAN);
  662.  
  663.     neffects = 1;
  664.     /* effect #0 is the input stream */
  665.     /* inform all effects about all relevant changes */
  666.     for(i = 0; i < MAXEFF; i++) {
  667.         efftab[i].name = efftabR[i].name = (char *) 0;
  668.         /* inform effect about signal information */
  669.         efftab[i].ininfo = informat.info;
  670.         efftabR[i].ininfo = informat.info;
  671.         efftab[i].outinfo = outformat.info;
  672.         efftabR[i].outinfo = outformat.info;
  673.         for(j = 0; j < 8; j++) {
  674.             memcpy(&efftab[i].loops[j], 
  675.                 &informat.loops[j], sizeof(struct loopinfo));
  676.             memcpy(&efftabR[i].loops[j], 
  677.                 &informat.loops[j], sizeof(struct loopinfo));
  678.         }
  679.         efftab[i].instr = informat.instr;
  680.         efftabR[i].instr = informat.instr;
  681.     }
  682.  
  683.     /* If not writing output, then just add the user specified effect.
  684.      * This is to avoid channel and rate averaging since you don't have
  685.      * a real output format.
  686.      */
  687.     if (! writing) {
  688.         neffects = 2;
  689.         efftab[1].name = effp->name;
  690.         if ((informat.info.channels == 2) &&
  691.            (! (effp->h->flags & EFF_MCHAN)))
  692.             efftabR[1].name = effp->name;
  693.     }
  694.     else if (soxpreview) {
  695.         /* to go faster, i suppose rate could come first if downsampling */
  696.         if (needchan && (informat.info.channels > outformat.info.channels))
  697.         {
  698.             if (needrate) {
  699.             neffects = 4;
  700.             efftab[1].name = "avg";
  701.             efftab[2].name = "rate";
  702.             setout(efftab[3], effp->name);
  703.         } else {
  704.             neffects = 3;
  705.             efftab[1].name = "avg";
  706.             setout(efftab[2], effp->name);
  707.         }
  708.         } else if (needchan && 
  709.             (informat.info.channels < outformat.info.channels)) {
  710.             if (needrate) {
  711.             neffects = 4;
  712.             efftab[1].name = effp->name;
  713.             efftab[1].outinfo.rate = informat.info.rate;
  714.             efftab[1].outinfo.channels = informat.info.channels;
  715.             efftab[2].name = "rate";
  716.             efftab[3].name = "avg";
  717.         } else {
  718.             neffects = 3;
  719.             efftab[1].name = effp->name;
  720.             efftab[1].outinfo.channels = informat.info.channels;
  721.             efftab[2].name = "avg";
  722.         }
  723.         } else {
  724.             if (needrate) {
  725.             neffects = 3;
  726.             efftab[1].name = effp->name;
  727.             efftab[1].outinfo.rate = informat.info.rate;
  728.             efftab[2].name = "rate";
  729.             if (informat.info.channels == 2)
  730.                 efftabR[2].name = "rate";
  731.         } else {
  732.             neffects = 2;
  733.             efftab[1].name = effp->name;
  734.         }
  735.         if ((informat.info.channels == 2) &&
  736.             (! (effp->h->flags & EFF_MCHAN)))
  737.                 efftabR[1].name = effp->name;
  738.         }
  739.     } else {    /* not preview mode */
  740.         /* [ sum to mono,] [ then rate,] then effect */
  741.         /* not the purest, but much faster */
  742.         if (needchan && 
  743.             (informat.info.channels > outformat.info.channels)) {
  744.             if (needrate && (informat.info.rate != outformat.info.rate)) {
  745.             neffects = 4;
  746.             efftab[1].name = "avg";
  747.             efftab[2].name = effp->name;
  748.             efftab[2].outinfo.rate = informat.info.rate;
  749.             efftab[2].outinfo.channels = informat.info.channels;
  750.             efftab[3].name = "rate";
  751.         } else {
  752.             neffects = 3;
  753.             efftab[1].name = "avg";
  754.             efftab[2].name = effp->name;
  755.             efftab[2].outinfo.rate = informat.info.rate;
  756.             efftab[2].outinfo.channels = informat.info.channels;
  757.         }
  758.         } else if (needchan && 
  759.             (informat.info.channels < outformat.info.channels)) {
  760.             if (needrate) {
  761.             neffects = 4;
  762.             efftab[1].name = effp->name;
  763.             if (! (effp->h->flags & EFF_MCHAN))
  764.                 efftabR[1].name = effp->name;
  765.             efftab[1].outinfo.rate = informat.info.rate;
  766.             efftab[1].outinfo.channels = informat.info.channels;
  767.             efftab[2].name = "resample";
  768.             efftab[3].name = "avg";
  769.         } else {
  770.             neffects = 3;
  771.             efftab[1].name = effp->name;
  772.             if (! (effp->h->flags & EFF_MCHAN))
  773.                 efftabR[1].name = effp->name;
  774.             efftab[1].outinfo.channels = informat.info.channels;
  775.             efftab[2].name = "avg";
  776.         }
  777.         } else {
  778.             if (needrate) {
  779.             neffects = 3;
  780.             efftab[1].name = effp->name;
  781.             efftab[1].outinfo.rate = informat.info.rate;
  782.             efftab[2].name = "resample";
  783.             if (informat.info.channels == 2)
  784.                 efftabR[2].name = "rate";
  785.         } else {
  786.             neffects = 2;
  787.             efftab[1].name = effp->name;
  788.         }
  789.         if ((informat.info.channels == 2) &&
  790.             (! (effp->h->flags & EFF_MCHAN)))
  791.                 efftabR[1].name = effp->name;
  792.         }
  793.     }
  794.  
  795.     for(i = 1; i < neffects; i++) {
  796.         /* pointer comparison OK here */
  797.         /* shallow copy of initialized effect data */
  798.         /* XXX this assumes that effect_getopt() doesn't malloc() */
  799.         if (efftab[i].name == effp->name) {
  800.             memcpy(&efftab[i], &eff, sizeof(struct effect));
  801.             if (efftabR[i].name) 
  802.                 memcpy(&efftabR[i], &eff, sizeof(struct effect));
  803.         } else {
  804.             /* set up & give default opts for added effects */
  805.             geteffect(&efftab[i]);
  806.             (* efftab[i].h->getopts)(&efftab[i],0,(char *)0);
  807.             if (efftabR[i].name) 
  808.                 memcpy(&efftabR[i], &efftab[i], 
  809.                 sizeof(struct effect));
  810.         }
  811.     }
  812.     
  813.     /* If a user doesn't specify an effect then a null entry could
  814.      * have been placed in the middle of the list above.  Remove
  815.      * those entries here.
  816.      */
  817.     for(i = 1; i < neffects; i++)
  818.         if (! strcmp(efftab[i].name, "null")) {
  819.         for(; i < neffects; i++) {
  820.             efftab[i] = efftab[i+1];
  821.             efftabR[i] = efftabR[i+1];
  822.         }
  823.         neffects--;
  824.         }
  825. }
  826.  
  827. /* Guido Van Rossum fix */
  828. void statistics() {
  829.     if (dovolume && clipped > 0)
  830.         report("Volume change clipped %d samples", clipped);
  831. }
  832.  
  833. LONG volumechange(y)
  834. LONG y;
  835. {
  836.     double y1;
  837.  
  838.     y1 = y * volume;
  839.     if (y1 < -2147483647.0) {
  840.         y1 = -2147483647.0;
  841.         clipped++;
  842.     }
  843.     else if (y1 > 2147483647.0) {
  844.         y1 = 2147483647.0;
  845.         clipped++;
  846.     }
  847.  
  848.     return y1;
  849. }
  850.  
  851. int filetype(fd)
  852. int fd;
  853. {
  854.     struct stat st;
  855.  
  856.     fstat(fd, &st);
  857.  
  858.     return st.st_mode & S_IFMT;
  859. }
  860.  
  861. char *usagestr = 
  862. "[ gopts ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]";
  863.  
  864. void usage(opt)
  865. char *opt;
  866. {
  867.     int i;
  868.     
  869.     fprintf(stderr, "%s: ", myname);
  870.     if (verbose || !opt)
  871.         fprintf(stderr, "%s\n\n", version());
  872.     fprintf(stderr, "Usage: %s\n\n", usagestr);
  873.     if (opt)
  874.         fprintf(stderr, "Failed at: %s\n", opt);
  875.     else {
  876.         fprintf(stderr,"gopts: -e -h -p -v volume -V\n\n");
  877.         fprintf(stderr,"fopts: -r rate -c channels -s/-u/-U/-A/-a/-g -b/-w/-l/-f/-d/-D -x\n\n");
  878.         fprintf(stderr, "effect: ");
  879.         for (i = 1; effects[i].name != NULL; i++) {
  880.         fprintf(stderr, "%s ", effects[i].name);
  881.         }
  882.         fprintf(stderr, "\n\neffopts: depends on effect\n\n");
  883.         fprintf(stderr, "Supported file formats: ");
  884.         for (i = 0; formats[i].names != NULL; i++) {
  885.         /* only print the first name */
  886.         fprintf(stderr, "%s ", formats[i].names[0]);
  887.         }
  888.         fputc('\n', stderr);
  889.     }
  890.     exit(1);
  891. }
  892.  
  893.  
  894. /* called from util.c:fail */
  895. void cleanup() {
  896.     /* Close the input file and outputfile before exiting*/
  897.     if (informat.fp)
  898.         fclose(informat.fp);
  899.     if (outformat.fp) {
  900.         fclose(outformat.fp);
  901.         /* remove the output file because we failed, if it's ours. */
  902.         /* Don't if its not a regular file. */
  903.         if (filetype(fileno(outformat.fp)) == S_IFREG)
  904.             REMOVE(outformat.filename);
  905.     }
  906. }
  907.