Logo Search packages:      
Sourcecode: rakarrack version File versions  Download package

Distorsion.C

/*
  ZynAddSubFX - a software synthesizer
 
  Distorsion.C - Distorsion effect
  Copyright (C) 2002-2005 Nasca Octavian Paul
  Author: Nasca Octavian Paul

  Modified for rakarrack by Josep Andreu
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License 
  as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License (version 2) for more details.

  You should have received a copy of the GNU General Public License (version 2)
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Distorsion.h"


/*
 * Waveshape (this is called by OscilGen::waveshape and Distorsion::process)
 */

void
waveshapesmps (int n, REALTYPE * smps, unsigned char type,
             unsigned char drive)
{
  int i;
  REALTYPE ws = drive / 127.0;
  ws = 1 - expf (-ws * 4);
  REALTYPE tmpv;

  switch (type)
    {
    case 1:
      ws = powf (10, ws * ws * 3.0) - 1.0 + 0.001;    //Arctangent
      for (i = 0; i < n; i++)
      smps[i] = atanf (smps[i] * ws) / atanf (ws);
      break;
    case 2:
      ws = ws * ws * 32.0 + 0.0001; //Asymmetric
      if (ws < 1.0)
      tmpv = sinf (ws) + 0.1;
      else
      tmpv = 1.1;
      for (i = 0; i < n; i++)
      {
        smps[i] = sinf (smps[i] * (0.1 + ws - ws * smps[i])) / tmpv;
      };
      break;
    case 3:
      ws = ws * ws * ws * 20.0 + 0.0001;  //Pow
      for (i = 0; i < n; i++)
      {
        smps[i] *= ws;
        if (fabsf (smps[i]) < 1.0)
          {
            smps[i] = (smps[i] - powf (smps[i], 3.0)) * 3.0;
            if (ws < 1.0)
            smps[i] /= ws;
          }
        else
          smps[i] = 0.0;
      };
      break;
    case 4:
      ws = ws * ws * ws * 32.0 + 0.0001;  //Sine
      if (ws < 1.57)
      tmpv = sinf (ws);
      else
      tmpv = 1.0;
      for (i = 0; i < n; i++)
      smps[i] = sinf (smps[i] * ws) / tmpv;
      break;
    case 5:
      ws = ws * ws + 0.000001;      //Quantisize
      for (i = 0; i < n; i++)
      smps[i] = floorf (smps[i] / ws + 0.15) * ws;
      break;
    case 6:
      ws = ws * ws * ws * 32 + 0.0001;    //Zigzag
      if (ws < 1.0)
      tmpv = sinf (ws);
      else
      tmpv = 1.0;
      for (i = 0; i < n; i++)
      smps[i] = asinf (sinf (smps[i] * ws)) / tmpv;
      break;
    case 7:
      ws = powf (2.0, -ws * ws * 8.0);    //Limiter
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i];
        if (fabsf (tmp) > ws)
          {
            if (tmp >= 0.0)
            smps[i] = 1.0;
            else
            smps[i] = -1.0;
          }
        else
          smps[i] /= ws;
      };
      break;
    case 8:
      ws = powf (2.0, -ws * ws * 8.0);    //Upper Limiter
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i];
        if (tmp > ws)
          smps[i] = ws;
        smps[i] *= 2.0;
      };
      break;
    case 9:
      ws = powf (2.0, -ws * ws * 8.0);    //Lower Limiter
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i];
        if (tmp < -ws)
          smps[i] = -ws;
        smps[i] *= 2.0;
      };
      break;
    case 10:
      ws = (powf (2.0, ws * 6.0) - 1.0) / powf (2.0, 6.0);  //Inverse Limiter
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i];
        if (fabsf (tmp) > ws)
          {
            if (tmp >= 0.0)
            smps[i] = tmp - ws;
            else
            smps[i] = tmp + ws;
          }
        else
          smps[i] = 0;
      };
      break;
    case 11:
      ws = powf (5, ws * ws * 1.0) - 1.0; //Clip
      for (i = 0; i < n; i++)
      smps[i] =
        smps[i] * (ws + 0.5) * 0.9999 - floorf (0.5 +
                                     smps[i] * (ws +
                                              0.5) * 0.9999);
      break;
    case 12:
      ws = ws * ws * ws * 30 + 0.001;     //Asym2
      if (ws < 0.3)
      tmpv = ws;
      else
      tmpv = 1.0;
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i] * ws;
        if ((tmp > -2.0) && (tmp < 1.0))
          smps[i] = tmp * (1.0 - tmp) * (tmp + 2.0) / tmpv;
        else
          smps[i] = 0.0;
      };
      break;
    case 13:
      ws = ws * ws * ws * 32.0 + 0.0001;  //Pow2
      if (ws < 1.0)
      tmpv = ws * (1 + ws) / 2.0;
      else
      tmpv = 1.0;
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i] * ws;
        if ((tmp > -1.0) && (tmp < 1.618034))
          smps[i] = tmp * (1.0 - tmp) / tmpv;
        else if (tmp > 0.0)
          smps[i] = -1.0;
        else
          smps[i] = -2.0;
      };
      break;
    case 14:
      ws = powf (ws, 5.0) * 80.0 + 0.0001;      //sigmoid
      if (ws > 10.0)
      tmpv = 0.5;
      else
      tmpv = 0.5 - 1.0 / (expf (ws) + 1.0);
      for (i = 0; i < n; i++)
      {
        REALTYPE tmp = smps[i] * ws;
        if (tmp < -10.0)
          tmp = -10.0;
        else if (tmp > 10.0)
          tmp = 10.0;
        tmp = 0.5 - 1.0 / (expf (tmp) + 1.0);
        smps[i] = tmp / tmpv;
      };
      break;
      //update to Distorsion::changepar (Ptype max) if there is added more waveshapings functions
    };

};


Distorsion::Distorsion (REALTYPE * efxoutl_, REALTYPE * efxoutr_)
{
  efxoutl = efxoutl_;
  efxoutr = efxoutr_;

  lpfl = new AnalogFilter (2, 22000, 1, 0);
  lpfr = new AnalogFilter (2, 22000, 1, 0);
  hpfl = new AnalogFilter (3, 20, 1, 0);
  hpfr = new AnalogFilter (3, 20, 1, 0);


  //default values
  Ppreset = 0;
  Pvolume = 50;
  Plrcross = 40;
  Pdrive = 90;
  Plevel = 64;
  Ptype = 0;
  Pnegate = 0;
  Plpf = 127;
  Phpf = 0;
  Pstereo = 0;
  Pprefiltering = 0;

  setpreset (Ppreset);
  cleanup ();
};

Distorsion::~Distorsion ()
{
  delete (lpfl);
  delete (lpfr);
  delete (hpfl);
  delete (hpfr);

};

/*
 * Cleanup the effect
 */
void
Distorsion::cleanup ()
{
  lpfl->cleanup ();
  hpfl->cleanup ();
  lpfr->cleanup ();
  hpfr->cleanup ();
};


/*
 * Apply the filters
 */

void
Distorsion::applyfilters (REALTYPE * efxoutl, REALTYPE * efxoutr)
{
  lpfl->filterout (efxoutl);
  hpfl->filterout (efxoutl);
  if (Pstereo != 0)
    {                   //stereo
      lpfr->filterout (efxoutr);
      hpfr->filterout (efxoutr);
    };

};


/*
 * Effect output
 */
void
Distorsion::out (REALTYPE * smpsl, REALTYPE * smpsr)
{
  int i;
  REALTYPE l, r, lout, rout;

  REALTYPE inputvol = powf (5.0, (Pdrive - 32.0) / 127.0);
  if (Pnegate != 0)
    inputvol *= -1.0;

  if (Pstereo != 0)
    {                   //Stereo
      for (i = 0; i < PERIOD; i++)
      {
        efxoutl[i] = smpsl[i] * inputvol * panning;
        efxoutr[i] = smpsr[i] * inputvol * (1.0 - panning);
      };
    }
  else
    {
      for (i = 0; i < PERIOD; i++)
      {
        efxoutl[i] =
          (smpsl[i] * panning + smpsr[i] * (1.0 - panning)) * inputvol;
      };
    };

  if (Pprefiltering != 0)
    applyfilters (efxoutl, efxoutr);

  //no optimised, yet (no look table)

  for (i = 0; i < PERIOD; i++)
    {
      efxoutl[i] *= 2.0;
      efxoutl[i] *= 2.0;
    }






  waveshapesmps (PERIOD, efxoutl, Ptype + 1, Pdrive);
  if (Pstereo != 0)
    waveshapesmps (PERIOD, efxoutr, Ptype + 1, Pdrive);

  if (Pprefiltering == 0)
    applyfilters (efxoutl, efxoutr);

  if (Pstereo == 0)
    for (i = 0; i < PERIOD; i++)
      efxoutr[i] = efxoutl[i];

  REALTYPE level = dB2rap (60.0 * Plevel / 127.0 - 40.0);
  for (i = 0; i < PERIOD; i++)
    {
      lout = efxoutl[i];
      rout = efxoutr[i];
      l = lout * (1.0 - lrcross) + rout * lrcross;
      r = rout * (1.0 - lrcross) + lout * lrcross;
      lout = l;
      rout = r;

      efxoutl[i] = lout * 2.0 * level;
      efxoutr[i] = rout * 2.0 * level;

    };

};


/*
 * Parameter control
 */
void
Distorsion::setvolume (unsigned char Pvolume)
{
  this->Pvolume = Pvolume;

  outvolume = Pvolume / 127.0;
  if (Pvolume == 0)
    cleanup ();

};

void
Distorsion::setpanning (unsigned char Ppanning)
{
  this->Ppanning = Ppanning;
  panning = (Ppanning + 0.5) / 127.0;
};


void
Distorsion::setlrcross (unsigned char Plrcross)
{
  this->Plrcross = Plrcross;
  lrcross = Plrcross / 127.0 * 1.0;
};

void
Distorsion::setlpf (unsigned char Plpf)
{
  this->Plpf = Plpf;
  REALTYPE fr = expf (powf (Plpf / 127.0, 0.5) * logf (25000.0)) + 40;
  lpfl->setfreq (fr);
  lpfr->setfreq (fr);
};

void
Distorsion::sethpf (unsigned char Phpf)
{
  this->Phpf = Phpf;
  REALTYPE fr = expf (powf (Phpf / 127.0, 0.5) * logf (25000.0)) + 20.0;
  hpfl->setfreq (fr);
  hpfr->setfreq (fr);
};


void
Distorsion::setpreset (unsigned char npreset)
{
  const int PRESET_SIZE = 11;
  const int NUM_PRESETS = 6;
  unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
    //Overdrive 1
    {84, 64, 35, 56, 40, 0, 0, 96, 0, 0, 0},
    //Overdrive 2
    {85, 64, 35, 29, 45, 1, 0, 127, 0, 0, 0},
    //Distorsion 1
    {0, 64, 0, 87, 14, 6, 0, 80, 30, 0, 1},
    //Distorsion 2
    {0, 64, 127, 87, 14, 0, 1, 80, 24, 0, 0},
    //Distorsion 3
    {0, 64, 127, 127, 12, 13, 0, 90, 16, 0, 1},
    //Guitar Amp
    {84, 64, 35, 63, 50, 2, 0, 55, 0, 0, 0}
  };


  if (npreset >= NUM_PRESETS)
    npreset = NUM_PRESETS - 1;
  for (int n = 0; n < PRESET_SIZE; n++)
    changepar (n, presets[npreset][n]);
  Ppreset = npreset;
  cleanup ();
};


void
Distorsion::changepar (int npar, unsigned char value)
{
  switch (npar)
    {
    case 0:
      setvolume (value);
      break;
    case 1:
      setpanning (value);
      break;
    case 2:
      setlrcross (value);
      break;
    case 3:
      Pdrive = value;
      break;
    case 4:
      Plevel = value;
      break;
    case 5:
      if (value > 13)
      value = 13;       //this must be increased if more distorsion types are added
      Ptype = value;
      break;
    case 6:
      if (value > 1)
      value = 1;
      Pnegate = value;
      break;
    case 7:
      setlpf (value);
      break;
    case 8:
      sethpf (value);
      break;
    case 9:
      if (value > 1)
      value = 1;
      Pstereo = value;
      break;
    case 10:
      Pprefiltering = value;
      break;
    };
};

unsigned char
Distorsion::getpar (int npar)
{
  switch (npar)
    {
    case 0:
      return (Pvolume);
      break;
    case 1:
      return (Ppanning);
      break;
    case 2:
      return (Plrcross);
      break;
    case 3:
      return (Pdrive);
      break;
    case 4:
      return (Plevel);
      break;
    case 5:
      return (Ptype);
      break;
    case 6:
      return (Pnegate);
      break;
    case 7:
      return (Plpf);
      break;
    case 8:
      return (Phpf);
      break;
    case 9:
      return (Pstereo);
      break;
    case 10:
      return (Pprefiltering);
      break;
    };
  return (0);                 //in case of bogus parameter number
};

Generated by  Doxygen 1.6.0   Back to index