home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / SoX / Source / flanger.c < prev    next >
C/C++ Source or Header  |  1999-07-18  |  8KB  |  303 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.  *     Flanger effect.
  12.  * 
  13.  * Flow diagram scheme:
  14.  *
  15.  *                                                 * gain-in  ___
  16.  * ibuff -----+--------------------------------------------->|   |
  17.  *            |      _______                                 |   |
  18.  *            |     |       |                      * decay   |   |
  19.  *            +---->| delay |------------------------------->| + |
  20.  *                  |_______|                                |   |
  21.  *                     /|\                                   |   |
  22.  *                      |                                    |___|
  23.  *                      |                                      | 
  24.  *              +---------------+      +------------------+    | * gain-out
  25.  *              | Delay control |<-----| modulation speed |    |
  26.  *              +---------------+      +------------------+    +----->obuff
  27.  *
  28.  *
  29.  * The delay is controled by a sine or triangle modulation.
  30.  *
  31.  * Usage: 
  32.  *   flanger gain-in gain-out delay decay speed [ -s | -t ]
  33.  *
  34.  * Where:
  35.  *   gain-in, decay :  0.0 ... 1.0      volume
  36.  *   gain-out :  0.0 ...      volume
  37.  *   delay :  0.0 ... 5.0 msec
  38.  *   speed :  0.1 ... 2.0 Hz       modulation
  39.  *   -s : modulation by sine (default)
  40.  *   -t : modulation by triangle
  41.  *
  42.  * Note:
  43.  *   when decay is close to 1.0, the samples may begin clipping or the output
  44.  *   can saturate! 
  45.  *
  46.  * Hint:
  47.  *   1 / out-gain > gain-in * ( 1 + decay )
  48.  *
  49. */
  50.  
  51. /*
  52.  * Sound Tools flanger effect file.
  53.  */
  54.  
  55. #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
  56. #ifdef HAVE_MALLOC_H
  57. #include <malloc.h>
  58. #endif
  59. #include <math.h>
  60. #include <string.h>
  61. #include "st.h"
  62.  
  63. #define MOD_SINE    0
  64. #define MOD_TRIANGLE    1
  65.  
  66. /* Private data for SKEL file */
  67. typedef struct flangerstuff {
  68.     int    modulation;
  69.     int    counter;            
  70.     int    phase;
  71.     double    *flangerbuf;
  72.     float    in_gain, out_gain;
  73.     float    delay, decay;
  74.     float    speed;
  75.     long    length;
  76.     int    *lookup_tab;
  77.     long    maxsamples, fade_out;
  78. } *flanger_t;
  79.  
  80. /* Private data for SKEL file */
  81.  
  82. LONG flanger_clip24(l)
  83. LONG l;
  84. {
  85.     if (l >= ((LONG)1 << 24))
  86.         return ((LONG)1 << 24) - 1;
  87.     else if (l <= -((LONG)1 << 24))
  88.         return -((LONG)1 << 24) + 1;
  89.     else
  90.         return l;
  91. }
  92.  
  93. /* This was very painful.  We need a sine library. */
  94.  
  95. void flanger_sine(buf, len, depth)
  96. int *buf;
  97. long len;
  98. long depth;
  99. {
  100.     long i;
  101.     double val;
  102.  
  103.     for (i = 0; i < len; i++) {
  104.         val = sin((double)i/(double)len * 2.0 * M_PI);
  105.         buf[i] = (int) ((1.0 + val) * depth / 2.0);
  106.     }
  107. }
  108.  
  109. void flanger_triangle(buf, len, depth)
  110. int *buf;
  111. long len;
  112. long depth;
  113. {
  114.     long i;
  115.     double val;
  116.  
  117.     for (i = 0; i < len / 2; i++) {
  118.         val = i * 2.0 / len;
  119.         buf[i] = (int) (val * depth);
  120.     }
  121.     for (i = len / 2; i < len ; i++) {
  122.         val = (len - i) * 2.0 / len;
  123.         buf[i] = (int) (val * depth);
  124.     }
  125. }
  126.  
  127. /*
  128.  * Process options
  129.  */
  130. void flanger_getopts(effp, n, argv) 
  131. eff_t effp;
  132. int n;
  133. char **argv;
  134. {
  135.     flanger_t flanger = (flanger_t) effp->priv;
  136.  
  137.     if (!((n == 5) || (n == 6)))
  138.         fail("Usage: flanger gain-in gain-out delay decay speed [ -s | -t ]");
  139.  
  140.     sscanf(argv[0], "%f", &flanger->in_gain);
  141.     sscanf(argv[1], "%f", &flanger->out_gain);
  142.     sscanf(argv[2], "%f", &flanger->delay);
  143.     sscanf(argv[3], "%f", &flanger->decay);
  144.     sscanf(argv[4], "%f", &flanger->speed);
  145.     flanger->modulation = MOD_SINE;
  146.     if ( n == 6 ) {
  147.         if ( !strcmp(argv[5], "-s"))
  148.             flanger->modulation = MOD_SINE;
  149.         else if ( ! strcmp(argv[5], "-t"))
  150.             flanger->modulation = MOD_TRIANGLE;
  151.         else
  152.                 fail("Usage: flanger gain-in gain-out delay decay speed [ -s | -t ]");
  153.     }
  154. }
  155.  
  156. /*
  157.  * Prepare for processing.
  158.  */
  159. void flanger_start(effp)
  160. eff_t effp;
  161. {
  162.     flanger_t flanger = (flanger_t) effp->priv;
  163.     int i;
  164.  
  165.     flanger->maxsamples = flanger->delay * effp->ininfo.rate / 1000.0;
  166.  
  167.     if ( flanger->in_gain < 0.0 )
  168.         fail("flanger: gain-in must be positive!\n");
  169.     if ( flanger->in_gain > 1.0 )
  170.         fail("flanger: gain-in must be less than 1.0!\n");
  171.     if ( flanger->out_gain < 0.0 )
  172.         fail("flanger: gain-out must be positive!\n");
  173.     if ( flanger->delay < 0.0 )
  174.         fail("flanger: delay must be positive!\n");
  175.     if ( flanger->delay > 5.0 )
  176.         fail("flanger: delay must be less than 5.0 msec!\n");
  177.     if ( flanger->speed < 0.1 )
  178.         fail("flanger: speed must be more than 0.1 Hz!\n");
  179.     if ( flanger->speed > 2.0 )
  180.         fail("flanger: speed must be less than 2.0 Hz!\n");
  181.     if ( flanger->decay < 0.0 )
  182.         fail("flanger: decay must be positive!\n" );
  183.     if ( flanger->decay > 1.0 )
  184.         fail("flanger: decay must be less that 1.0!\n" );
  185.     /* Be nice and check the hint with warning, if... */
  186.     if ( flanger->in_gain * ( 1.0 + flanger->decay ) > 1.0 / flanger->out_gain )
  187.         warn("flanger: warning >>> gain-out can cause saturation or clipping of output <<<");
  188.  
  189.     flanger->length = effp->ininfo.rate / flanger->speed;
  190.  
  191.     if (! (flanger->flangerbuf = 
  192.         (double *) malloc(sizeof (double) * flanger->maxsamples)))
  193.         fail("flanger: Cannot malloc %d bytes!\n", 
  194.             sizeof(double) * flanger->maxsamples);
  195.     for ( i = 0; i < flanger->maxsamples; i++ )
  196.         flanger->flangerbuf[i] = 0.0;
  197.     if (! (flanger->lookup_tab = 
  198.         (int *) malloc(sizeof (int) * flanger->length)))
  199.         fail("flanger: Cannot malloc %d bytes!\n", 
  200.             sizeof(int) * flanger->length);
  201.  
  202.     if ( flanger->modulation == MOD_SINE )
  203.         flanger_sine(flanger->lookup_tab, flanger->length, 
  204.             flanger->maxsamples - 1);
  205.     else
  206.         flanger_triangle(flanger->lookup_tab, flanger->length, 
  207.             flanger->maxsamples - 1);
  208.     flanger->counter = 0;
  209.     flanger->phase = 0;
  210.     flanger->fade_out = flanger->maxsamples;
  211. }
  212.  
  213. /*
  214.  * Processed signed long samples from ibuf to obuf.
  215.  * Return number of samples processed.
  216.  */
  217.  
  218. void flanger_flow(effp, ibuf, obuf, isamp, osamp)
  219. eff_t effp;
  220. LONG *ibuf, *obuf;
  221. int *isamp, *osamp;
  222. {
  223.     flanger_t flanger = (flanger_t) effp->priv;
  224.     int len, done;
  225.     
  226.     double d_in, d_out;
  227.     LONG out;
  228.  
  229.     len = ((*isamp > *osamp) ? *osamp : *isamp);
  230.     for(done = 0; done < len; done++) {
  231.         /* Store delays as 24-bit signed longs */
  232.         d_in = (double) *ibuf++ / 256;
  233.         /* Compute output first */
  234.         d_out = d_in * flanger->in_gain;
  235.         d_out += flanger->flangerbuf[(flanger->maxsamples + 
  236.     flanger->counter - flanger->lookup_tab[flanger->phase]) % 
  237.     flanger->maxsamples] * flanger->decay;
  238.         /* Adjust the output volume and size to 24 bit */
  239.         d_out = d_out * flanger->out_gain;
  240.         out = flanger_clip24((LONG) d_out);
  241.         *obuf++ = out * 256;
  242.         /* Mix decay of delay and input */
  243.         flanger->flangerbuf[flanger->counter] = d_in;
  244.         flanger->counter = 
  245.             ( flanger->counter + 1 ) % flanger->maxsamples;
  246.         flanger->phase  = ( flanger->phase + 1 ) % flanger->length;
  247.     }
  248.     /* processed all samples */
  249. }
  250.  
  251. /*
  252.  * Drain out reverb lines. 
  253.  */
  254. void flanger_drain(effp, obuf, osamp)
  255. eff_t effp;
  256. LONG *obuf;
  257. int *osamp;
  258. {
  259.     flanger_t flanger = (flanger_t) effp->priv;
  260.     int done;
  261.     
  262.     double d_in, d_out;
  263.     LONG out;
  264.  
  265.     done = 0;
  266.     while ( ( done < *osamp ) && ( done < flanger->fade_out ) ) {
  267.         d_in = 0;
  268.         d_out = 0;
  269.         /* Compute output first */
  270.         d_out += flanger->flangerbuf[(flanger->maxsamples + 
  271.     flanger->counter - flanger->lookup_tab[flanger->phase]) % 
  272.     flanger->maxsamples] * flanger->decay;
  273.         /* Adjust the output volume and size to 24 bit */
  274.         d_out = d_out * flanger->out_gain;
  275.         out = flanger_clip24((LONG) d_out);
  276.         *obuf++ = out * 256;
  277.         /* Mix decay of delay and input */
  278.         flanger->flangerbuf[flanger->counter] = d_in;
  279.         flanger->counter = 
  280.             ( flanger->counter + 1 ) % flanger->maxsamples;
  281.         flanger->phase  = ( flanger->phase + 1 ) % flanger->length;
  282.         done++;
  283.         flanger->fade_out--;
  284.     }
  285.     /* samples playd, it remains */
  286.     *osamp = done;
  287. }
  288.  
  289. /*
  290.  * Clean up flanger effect.
  291.  */
  292. void flanger_stop(effp)
  293. eff_t effp;
  294. {
  295.     flanger_t flanger = (flanger_t) effp->priv;
  296.  
  297.     free((char *) flanger->flangerbuf);
  298.     flanger->flangerbuf = (double *) -1;   /* guaranteed core dump */
  299.     free((char *) flanger->lookup_tab);
  300.     flanger->lookup_tab = (int *) -1;   /* guaranteed core dump */
  301. }
  302.  
  303.