octal-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Octal-dev] Octal converted code for SoX flanger.c (soxflanger.c)


From: Neil Nelson
Subject: [Octal-dev] Octal converted code for SoX flanger.c (soxflanger.c)
Date: Sat, 24 Jun 2000 09:58:28 -0700

/*   SOXFLANGER.C
*
* This code has been adapted from from the SoX flanger.c code:
*
* August 24, 1998
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose.  This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* Conversion to Octal made by:
*
* Copyright 2000 Neil Nelson <address@hidden> June 24, 2000.
*
* This software is distributed under the terms of the
* GNU General Public License (GPL). Read the included file
* COPYING for more information.
*
*
*    Flanger effect.
*
* Flow diagram scheme:
*
*                                                 * gain-in  ___
* ibuff -----+--------------------------------------------->|   |
*            |      _______                                 |   |
*            |     |       |                      * sxfdecay   |   |
*            +---->| sxfdelay |------------------------------->| + |
*                  |_______|                                |   |
*                     /|\                                   |   |
*                      |                                    |___|
*                      |                                      |
*              +---------------+      +------------------+    | * gain-out
*              | Delay control |<-----| modulation speed |    |
*              +---------------+      +------------------+    +----->obuff
*
*
* The sxfdelay is controled by a sine or triangle modulation.
*
* Usage:
*   flanger gain-in gain-out sxfdelay sxfdecay speed [ -s | -t ]
*
* Where:
*   gain-in, sxfdecay :  0.0 ... 1.0      volume
*   gain-out :  0.0 ...      volume
*   sxfdelay :  0.0 ... 5.0 msec
*   speed :  0.1 ... 2.0 Hz       modulation
*   modulation by sine (default) : 0
*   modulation by triangle : 1
*
* Note:
*   when sxfdecay is close to 1.0, the samples may begin clipping or the output
*   can saturate!
*
* Hint:
*   1 / out-gain > gain-in * ( 1 + sxfdecay )
*
* Potential improvements:
*   (1) Is a clipping value needed?
*
*   (2) Should the fractional phase shift value be used to interpolate the two
*       adjacent delay samples?
*
*   (3) When the speed, delay, or modulation type are changed on an update, is there
*       sufficient distortion to require some attempt to smooth that update?
*
*   (4) How about allowing an option to split the delay portion to m->rout so that
*       the unchanged sound goes to one side (left) and the flanger sound goes to the
*       other?  Or keep the current mixed flanger output to one side and invert the
*       phase shift and mix that with the input to the other side.  I.e., have left
*       and right be 180 (or other) degs. out-of-phase.
*
*   (5) Allow for greater ranges on delay and speed.
*
*   (6) Provide for additional phase shift patterns other than sine and triangle.
*       Allow triangle mid-point to adjusted arbitrarily left and right to change
*       upward and downward slopes.  Mix together multiple phase shift patterns.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "util.h"
#include "machine.h"

#define PI2 (6.28318530717958465692)
#define MOD_SINE 0
#define MOD_TRIANGLE 1

/*  The parameters are:  gain_in, gain_out, decay, delay, speed, modulation_type */
enum {ix_gain_in, ix_gain_out, ix_sxfdecay, ix_sxfdelay, ix_speed, ix_mod_type} param_index;

param_spec sxf_params[] = {
   /*  First parameter: gain_in. */
   {
   small,
   slider,
   "Gain In",
   "Gain In",
   0,           /* 0 gain */
   255,         /* Gain of 1 */
   128          /* Approx. 0.5 */
   },

   /*  Second parameter: gain_out. */
   {
   small,
   slider,
   "Gain Out",
   "Gain Out",
   0,           /* 0 gain */
   255,         /* Gain of 1 */
   255
   },

   /*  Third parameter: decay (sxfdecay). */
   {
   small,
   slider,
   "Decay",
   "Decay",
   0,
   255,         /* 1 */
   128          /* Approx. 0.5 */
   },

   /*  Fourth parameter: delay (sxfdelay). */
   {
   small,
   slider,
   "Delay",
   "Delay: 0 to 5 msec.",
   1,           /* 1/51 msec. delay  */
   255,         /* Maximum 5 msec. delay */
   151          /* Approx. 3 msec. delay */
   },

   /*  Fifth parameter: speed. */
   {
   small,
   slider,
   "Speed",
   "Modulation Speed: 0 to 2 Hz.",
   10,          /* Approx. 0.078 Hz */
   255,         /* 2 Hz */
   128          /* Approx. 1 Hz */
   },

   /*  Sixth parameter: modulation type (mod_type). */
   {
   small,
   slider,
   "Modulation"
   "Modulation type: 0=sine (default), 1=triangle",
   0,           /* Sine  */
   1,           /* Triangle  */
   0            /* Sine by default */
   }
};

/*  State of the soxflanger. */

typedef struct {
   float   in_gain;
   float   out_gain;
   float   sxfdecay;
   float   sxfdelay;
   float   maxsxfdelay;
   float   speed;
   int     mod_type;
   long    smpsxfdelay;
   long    maxsmpsxfdelay;
   long    depth;
   long    phz_width;
   samp*   dlybuf;
   int*    tbl_lookup;
   int     dlycounter;
   int     phase;
//   float   clip; // Put in after clipping issue decided.
} sxf_state;

int ox_init(machine_type *t) {
   t->long_name = "soxflanger (Mueller, Nelson, et al.)";
   t->short_name = "soxflanger";
   t->max_tracks = 1;
   t->input_channels = 1;
   t->output_channels = 1;
   t->num_params = 5;
   t->param_specs = sxf_params;

   return 1;
}

void ox_create(machine *m) {
   sxf_state *s;
   s = (sxf_state*) malloc(sizeof(sxf_state));

   /* Set defaults */
   s->in_gain = 128.0/255.0;    /* Approx. 0.5 */
   s->out_gain = 1.0;
   s->sxfdecay = 128.0/255.0;   /* Approx. 0.5 */
   s->sxfdelay = 151.0/255.0;   /* Approx. 3 msecs */
   s->smpsxfdelay = (long)(s->sxfdelay * ((float)OX_SAMPLING_RATE) / 1000.0 + 0.5);

   s->depth = s->smpsxfdelay - 1;
   s->maxsxfdelay = 5.0;        /* 5 msecs */
   s->maxsmpsxfdelay = (long)(s->maxsxfdelay * ((float)OX_SAMPLING_RATE) / 1000.0
                       + 0.5);

   s->speed = 1.0;              /* 1 Hz */
   s->mod_type = 0;             /* Use sine modulation */
   s->phz_width = (long)(((float)OX_SAMPLING_RATE) / s->speed + 0.5);

   s->dlycounter = 1; /* Start at 1 to account for add of 1 in phase shift below */
   s->phase = 0;

//   s->clip = ?; // Put in after clipping issue decided.

   s->dlybuf = (samp*) malloc(s->maxsmpsxfdelay * sizeof(samp));
//   memset(s->dlybuf, 0, s->maxsmpsxfdelay * sizeof(samp)); // Unnecessary

   m->state = (void *) s;
   return;
}

void ox_destroy(machine *m) {
   free( ((sxf_state*)(m->state)) -> dlybuf);
   free(m->state);
   m->state = NULL;
   return;
}

void ox_update(machine *m) {
   sxf_state *s = (sxf_state *) m->state;
   param temp;

   temp = m->params[0][ix_gain_in];
   if (temp != nochange) {
      if (temp < 0)   temp = 0;
      if (temp > 255) temp = 255;
      s->in_gain = ((float)temp) / 255.0;
   }

   temp = m->params[0][ix_gain_out];
   if (temp != nochange) {
      if (temp < 0)   temp = 0;
      if (temp > 255) temp = 255;
      s->out_gain = ((float)temp) / 255.0;
   }

   temp = m->params[0][ix_sxfdecay];
   if (temp != nochange) {
      if (temp < 0)   temp = 0;
      if (temp > 255) temp = 255;
      s->sxfdecay = ((float)temp) / 255.0;
   }

   temp = m->params[0][ix_sxfdelay];
   if (temp != nochange) {
      if (temp < 1)   temp = 1;
      if (temp > 255) temp = 255;
      s->sxfdelay = ((float)temp) / 255.0 * 5.0;
      s->smpsxfdelay = (long)(s->sxfdelay * ((float)OX_SAMPLING_RATE) / 1000.0 + 0.5);
      s->depth = s->smpsxfdelay - 1;
   }

   temp = m->params[0][ix_speed];
   if (temp != nochange) {
      if (temp < 10)  temp = 10;
      if (temp > 255) temp = 255;
      s->speed = ((float)temp) / 255.0 * 2.0;
      s->phz_width = (long)(((float)OX_SAMPLING_RATE) / s->speed + 0.5);
   }

   temp = m->params[0][ix_mod_type];
   if (temp != nochange) {
      if (temp > 1 || temp < 0) temp = 0;
      s->mod_type = temp;
   }

   return;
}

const char *ox_desc(int which_param, param value) {
   static char temp_string[80];
   float user_value;
   int percent;

   sprintf(temp_string, "ERROR");

   if (which_param == ix_gain_in || which_param == ix_gain_out
                                 || which_param == ix_sxfdecay) {
      user_value = ((float)value) / 255.0;
      percent = (int)(user_value * 100.0 + 0.5);
      sprintf(temp_string, "%d%%", percent);
   }

   else if (which_param == ix_sxfdelay) {
      user_value = (float)value / 255.0 * 5.0;
      if (user_value == 0.0)
         sprintf(temp_string, "Delay must be greater than 0 msec.");

      else if (user_value > 5.0)
         sprintf(temp_string, "Delay must be not greater than 5 msec.");

      else sprintf(temp_string, "%3.2f", user_value);
   }

   else if (which_param == ix_speed) {
      user_value = ((float) value) / 255.0 * 2.0;
      if (user_value < 0.078)
         sprintf(temp_string, "Speed must be not less than .1 Hz (10): %3.2f",
                 user_value);

      else if (user_value > 2.0)
         sprintf(temp_string, "Speed must be not greater than 2 Hz: %3.2f",
                 user_value);

      else sprintf(temp_string, "%3.2f", user_value);
   }

   else if (which_param == ix_mod_type) {
      switch (value) {
         case 0  : sprintf(temp_string, "Sine"); break;
         case 1  : sprintf(temp_string, "Triangle"); break;
         default : sprintf(temp_string,
                   "Error: Modulation type must be 0 for sine or 1 for triangle.");
      }
   }

/* Clipping - Be nice and check the hint with warning, if...
   if ( flanger->in_gain * ( 1.0 + flanger->sxfdecay ) > 1.0 / flanger->out_gain )
      warn("flanger: warning >>> gain-out can cause saturation or clipping of output <<<");
*/

}

int ox_work(machine *m, int block_size) {
   sxf_state *s = (sxf_state *) m->state;

   samp* mlout;
   samp* mrout;
   samp* mlin;
   samp* dlybf;
   int i, modtype, x_phz, dlyctr;
   long phzwidth, phaz, dly;
   float x_flt, ingain, outgain, dcy, phzdepth, phz2depth, phz2width;
   double pi2phzwdth;
//   float hig_clip, low_clip;

//   hig_clip = s->clip;
//   low_clip = 0.0 - s->clip;

   /* Speed-up variables */
   mlout = m->lout;
   mrout = m->rout;
   mlin = m->lin;
   dlybf = s->dlybuf;
   modtype = s->mod_type;
   ingain = s->in_gain;
   outgain = s->out_gain;
   phzwidth = s->phz_width;
   phzdepth = (float)s->depth;
   phaz = s->phase;
   dlyctr = s->dlycounter;
   dly = s->smpsxfdelay;
   dcy = s->sxfdecay;

   pi2phzwdth = PI2 / ((double)phzwidth);
   phz2width = 2.0 / ((float)phzwidth);
   phz2depth = phzdepth / 2.0;

   for(i = 0; i < block_size; i++) {

      /* Compute output first. */
      mlout[i] = mlin[i] * ingain;

      if (modtype == MOD_SINE) {

         // Get sine phase shift. 1 added to correct noise at 0.
         x_flt = (float) sin(((double)phaz) * pi2phzwdth);
         x_phz = (int) ((1.0 + x_flt) * phz2depth + 0.5) + 1;
      }

      else { // modtype == MOD_TRIANGLE

         // Compute triangle - ramp up and down.
         if (phaz < (phzwidth / 2)) { // Ramp up
            x_flt = ((float)phaz) * phz2width;
            x_phz = (int)(x_flt * phzdepth) + 1;
         }

         else { // Ramp down
            x_flt = (float)(phzwidth - phaz) * phz2width;
            x_phz = (int)(x_flt * phzdepth) + 1;
         }
      }

      mlout[i] += dlybf[(dly + dlyctr - x_phz) % dly] * dcy;

      /* Adjust the output volume. */
      mlout[i] *= outgain;

      /* Check for clipping.  Not implemented. */
//      if    (mlout[i] > hig_clip)   mlout[i] = hig_clip;
//      else if (mlout[i] < low_clip)   mlout[i] = low_clip;

      /* Mix sxfdecay of sxfdelay and input. */
      dlybf[dlyctr] = mlin[i];

      /* Move delay counter and phase positions forward.*/
      dlyctr = (dlyctr + 1) % dly;
      phaz  = (phaz + 1) % phzwidth;
   }

   /* Save speedup variables to state. */
   s->dlycounter = dlyctr;
   s->phase = phaz;
   return 1;
}

void ox_track(machine *m, int change) {
}
 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]