home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / SoX / Source / echo.c < prev    next >
C/C++ Source or Header  |  1999-07-18  |  7KB  |  264 lines

  1. /*
  2.  * August 24, 1998
  3.  * Copyright (C) 1998 Juergen Mueller And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Juergen Mueller And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * This is the "echo.c" while the old "echo.c" from version 12 moves to
  12.  * "reverb.c" satisfying the defintions made in the Guitar FX FAQ.
  13.  *
  14.  *
  15.  * Echo effect for dsp.
  16.  * 
  17.  * Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ):
  18.  *
  19.  *        * gain-in                                              ___
  20.  * ibuff -----------+------------------------------------------>|   |
  21.  *                  |       _________                           |   |
  22.  *                  |      |         |                * decay 1 |   |
  23.  *                  +----->| delay 1 |------------------------->|   |
  24.  *                  |      |_________|                          |   |
  25.  *                  |            _________                      | + |
  26.  *                  |           |         |           * decay 2 |   |
  27.  *                  +---------->| delay 2 |-------------------->|   |
  28.  *                  |           |_________|                     |   |
  29.  *                  :                 _________                 |   |
  30.  *                  |                |         |      * decay n |   |
  31.  *                  +--------------->| delay n |--------------->|___|
  32.  *                                   |_________|                  | 
  33.  *                                                                | * gain-out
  34.  *                                                                |
  35.  *                                                                +----->obuff
  36.  *
  37.  * Usage: 
  38.  *   echo gain-in gain-out delay-1 decay-1 [delay-2 decay-2 ... delay-n decay-n]
  39.  *
  40.  * Where:
  41.  *   gain-in, decay-1 ... decay-n :  0.0 ... 1.0      volume
  42.  *   gain-out :  0.0 ...      volume
  43.  *   delay-1 ... delay-n :  > 0.0 msec
  44.  *
  45.  * Note:
  46.  *   when decay is close to 1.0, the samples can begin clipping and the output
  47.  *   can saturate! 
  48.  *
  49.  * Hint:
  50.  *   1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n )
  51.  *
  52. */
  53.  
  54. /*
  55.  * Sound Tools reverb effect file.
  56.  */
  57.  
  58. #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
  59. #ifdef HAVE_MALLOC_H
  60. #include <malloc.h>
  61. #endif
  62. #include <math.h>
  63. #include "st.h"
  64.  
  65. #define DELAY_BUFSIZ ( 50L * MAXRATE )
  66. #define MAX_ECHOS 7    /* 24 bit x ( 1 + MAX_ECHOS ) = */
  67.             /* 24 bit x 8 = 32 bit !!!    */
  68.  
  69. /* Private data for SKEL file */
  70. typedef struct echostuff {
  71.     int    counter;            
  72.     int    num_delays;
  73.     double    *delay_buf;
  74.     float    in_gain, out_gain;
  75.     float    delay[MAX_ECHOS], decay[MAX_ECHOS];
  76.     long    samples[MAX_ECHOS], maxsamples, fade_out;
  77. } *echo_t;
  78.  
  79. /* Private data for SKEL file */
  80.  
  81.  
  82. /* If we are not carefull with the output volume */
  83. LONG echo_clip24(l)
  84. LONG l;
  85. {
  86.     if (l >= ((LONG)1 << 24))
  87.         return ((LONG)1 << 24) - 1;
  88.     else if (l <= -((LONG)1 << 24))
  89.         return -((LONG)1 << 24) + 1;
  90.     else
  91.         return l;
  92. }
  93.  
  94.  
  95.  
  96. /*
  97.  * Process options
  98.  */
  99. void echo_getopts(effp, n, argv) 
  100. eff_t effp;
  101. int n;
  102. char **argv;
  103. {
  104.     echo_t echo = (echo_t) effp->priv;
  105.     int i;
  106.  
  107.     echo->num_delays = 0;
  108.  
  109.     if ((n < 4) || (n % 2))
  110.         fail("Usage: echo gain-in gain-out delay decay [ delay decay ... ]");
  111.  
  112.     i = 0;
  113.     sscanf(argv[i++], "%f", &echo->in_gain);
  114.     sscanf(argv[i++], "%f", &echo->out_gain);
  115.     while (i < n) {
  116.         if ( echo->num_delays >= MAX_ECHOS )
  117.             fail("echo: to many delays, use less than %i delays",
  118.                 MAX_ECHOS);
  119.         /* Linux bug and it's cleaner. */
  120.         sscanf(argv[i++], "%f", &echo->delay[echo->num_delays]);
  121.         sscanf(argv[i++], "%f", &echo->decay[echo->num_delays]);
  122.         echo->num_delays++;
  123.     }
  124. }
  125.  
  126. /*
  127.  * Prepare for processing.
  128.  */
  129. void echo_start(effp)
  130. eff_t effp;
  131. {
  132.     echo_t echo = (echo_t) effp->priv;
  133.     int i;
  134.     float sum_in_volume;
  135.     long j;
  136.  
  137.     echo->maxsamples = 0L;
  138.     if ( echo->in_gain < 0.0 )
  139.         fail("echo: gain-in must be positive!\n");
  140.     if ( echo->in_gain > 1.0 )
  141.         fail("echo: gain-in must be less than 1.0!\n");
  142.     if ( echo->out_gain < 0.0 )
  143.         fail("echo: gain-in must be positive!\n");
  144.     for ( i = 0; i < echo->num_delays; i++ ) {
  145.         echo->samples[i] = echo->delay[i] * effp->ininfo.rate / 1000.0;
  146.         if ( echo->samples[i] < 1 )
  147.             fail("echo: delay must be positive!\n");
  148.         if ( echo->samples[i] > DELAY_BUFSIZ )
  149.             fail("echo: delay must be less than %g seconds!\n",
  150.                 DELAY_BUFSIZ / (float) effp->ininfo.rate );
  151.         if ( echo->decay[i] < 0.0 )
  152.             fail("echo: decay must be positive!\n" );
  153.         if ( echo->decay[i] > 1.0 )
  154.             fail("echo: decay must be less than 1.0!\n" );
  155.         if ( echo->samples[i] > echo->maxsamples )
  156.             echo->maxsamples = echo->samples[i];
  157.     }
  158.     if (! (echo->delay_buf = (double *) malloc(sizeof (double) * echo->maxsamples)))
  159.         fail("echo: Cannot malloc %d bytes!\n", 
  160.             sizeof(long) * echo->maxsamples);
  161.     for ( j = 0; j < echo->maxsamples; ++j )
  162.         echo->delay_buf[j] = 0.0;
  163.     /* Be nice and check the hint with warning, if... */
  164.     sum_in_volume = 1.0;
  165.     for ( i = 0; i < echo->num_delays; i++ ) 
  166.         sum_in_volume += echo->decay[i];
  167.     if ( sum_in_volume * echo->in_gain > 1.0 / echo->out_gain )
  168.         warn("echo: warning >>> gain-out can cause saturation of output <<<");
  169.     echo->counter = 0;
  170.     echo->fade_out = echo->maxsamples;
  171. }
  172.  
  173. /*
  174.  * Processed signed long samples from ibuf to obuf.
  175.  * Return number of samples processed.
  176.  */
  177.  
  178. void echo_flow(effp, ibuf, obuf, isamp, osamp)
  179. eff_t effp;
  180. LONG *ibuf, *obuf;
  181. int *isamp, *osamp;
  182. {
  183.     echo_t echo = (echo_t) effp->priv;
  184.     int len, done;
  185.     int j;
  186.     
  187.     double d_in, d_out;
  188.     LONG out;
  189.  
  190.     len = ((*isamp > *osamp) ? *osamp : *isamp);
  191.     for(done = 0; done < len; done++) {
  192.         /* Store delays as 24-bit signed longs */
  193.         d_in = (double) *ibuf++ / 256;
  194.         /* Compute output first */
  195.         d_out = d_in * echo->in_gain;
  196.         for ( j = 0; j < echo->num_delays; j++ ) {
  197.             d_out += echo->delay_buf[ 
  198. (echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples] 
  199.             * echo->decay[j];
  200.         }
  201.         /* Adjust the output volume and size to 24 bit */
  202.         d_out = d_out * echo->out_gain;
  203.         out = echo_clip24((LONG) d_out);
  204.         *obuf++ = out * 256;
  205.         /* Store input in delay buffer */
  206.         echo->delay_buf[echo->counter] = d_in;
  207.         /* Adjust the counter */
  208.         echo->counter = ( echo->counter + 1 ) % echo->maxsamples;
  209.     }
  210.     /* processed all samples */
  211. }
  212.  
  213. /*
  214.  * Drain out reverb lines. 
  215.  */
  216. void echo_drain(effp, obuf, osamp)
  217. eff_t effp;
  218. LONG *obuf;
  219. int *osamp;
  220. {
  221.     echo_t echo = (echo_t) effp->priv;
  222.     double d_in, d_out;
  223.     LONG out;
  224.     int j;
  225.     long done;
  226.  
  227.     done = 0;
  228.     /* drain out delay samples */
  229.     while ( ( done < *osamp ) && ( done < echo->fade_out ) ) {
  230.         d_in = 0;
  231.         d_out = 0;
  232.         for ( j = 0; j < echo->num_delays; j++ ) {
  233.             d_out += echo->delay_buf[ 
  234. (echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples] 
  235.             * echo->decay[j];
  236.         }
  237.         /* Adjust the output volume and size to 24 bit */
  238.         d_out = d_out * echo->out_gain;
  239.         out = echo_clip24((LONG) d_out);
  240.         *obuf++ = out * 256;
  241.         /* Store input in delay buffer */
  242.         echo->delay_buf[echo->counter] = d_in;
  243.         /* Adjust the counters */
  244.         echo->counter = ( echo->counter + 1 ) % echo->maxsamples;
  245.         done++;
  246.         echo->fade_out--;
  247.     };
  248.     /* samples played, it remains */
  249.     *osamp = done;
  250. }
  251.  
  252. /*
  253.  * Clean up reverb effect.
  254.  */
  255. void echo_stop(effp)
  256. eff_t effp;
  257. {
  258.     echo_t echo = (echo_t) effp->priv;
  259.  
  260.     free((char *) echo->delay_buf);
  261.     echo->delay_buf = (double *) -1;   /* guaranteed core dump */
  262. }
  263.  
  264.