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

Reverb.C

/*
  ZynAddSubFX - a software synthesizer
 
  Reverb.C - Reverberation 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 <math.h>
#include <stdlib.h>
#include "Reverb.h"

/*TODO: EarlyReflections,Prdelay,Perbalance */

Reverb::Reverb (REALTYPE * efxoutl_, REALTYPE * efxoutr_)
{
  efxoutl = efxoutl_;
  efxoutr = efxoutr_;
  inputbuf = new REALTYPE[PERIOD];
  //filterpars=NULL;


  //defaults
  Ppreset = 0;
  Pvolume = 48;
  Ppan = 64;
  Ptime = 64;
  Pidelay = 40;
  Pidelayfb = 0;
  Prdelay = 0;
  Plpf = 127;
  Phpf = 0;
  Perbalance = 64;
  Plohidamp = 80;
  Ptype = 1;
  Proomsize = 64;
  roomsize = 1.0;
  rs = 1.0;

  for (int i = 0; i < REV_COMBS * 2; i++)
    {
      comblen[i] = 800 + (int) (RND * 1400);
      combk[i] = 0;
      lpcomb[i] = 0;
      combfb[i] = -0.97;
      comb[i] = NULL;
    };

  for (int i = 0; i < REV_APS * 2; i++)
    {
      aplen[i] = 500 + (int) (RND * 500);
      apk[i] = 0;
      ap[i] = NULL;
    };

  lpf = NULL;
  hpf = NULL;                 //no filter
  idelay = NULL;

  setpreset (Ppreset);
  cleanup ();                 //do not call this before the comb initialisation
};


Reverb::~Reverb ()
{
  int i;
  if (idelay != NULL)
    delete idelay;
  if (hpf != NULL)
    delete hpf;
  if (lpf != NULL)
    delete lpf;

  for (i = 0; i < REV_APS * 2; i++)
    delete ap[i];
  for (i = 0; i < REV_COMBS * 2; i++)
    delete comb[i];

  delete[]inputbuf;
};

/*
 * Cleanup the effect
 */
void
Reverb::cleanup ()
{
  int i, j;
  for (i = 0; i < REV_COMBS * 2; i++)
    {
      lpcomb[i] = 0.0;
      for (j = 0; j < comblen[i]; j++)
      comb[i][j] = 0.0;
    };

  for (i = 0; i < REV_APS * 2; i++)
    for (j = 0; j < aplen[i]; j++)
      ap[i][j] = 0.0;

  if (idelay != NULL)
    for (i = 0; i < idelaylen; i++)
      idelay[i] = 0.0;

  if (hpf != NULL)
    hpf->cleanup ();
  if (lpf != NULL)
    lpf->cleanup ();


};

/*
 * Process one channel; 0=left,1=right
 */
void
Reverb::processmono (int ch, REALTYPE * output)
{
  int i, j;
  REALTYPE fbout, tmp;
  //TODO: implement the high part from lohidamp

  for (j = REV_COMBS * ch; j < REV_COMBS * (ch + 1); j++)
    {

      int ck = combk[j];
      int comblength = comblen[j];
      REALTYPE lpcombj = lpcomb[j];

      for (i = 0; i < PERIOD; i++)
      {
        fbout = comb[j][ck] * combfb[j];
        fbout = fbout * (1.0 - lohifb) + (lpcombj * lohifb);
        lpcombj = fbout;

        comb[j][ck] = inputbuf[i] + fbout;
        output[i] += fbout;

        if ((++ck) >= comblength)
          ck = 0;
      };

      combk[j] = ck;
      lpcomb[j] = lpcombj;
    };

  for (j = REV_APS * ch; j < REV_APS * (1 + ch); j++)
    {
      int ak = apk[j];
      int aplength = aplen[j];
      for (i = 0; i < PERIOD; i++)
      {
        tmp = ap[j][ak];
        ap[j][ak] = 0.7 * tmp + output[i];
        output[i] = tmp - 0.7 * ap[j][ak];
        if ((++ak) >= aplength)
          ak = 0;
      };
      apk[j] = ak;
    };
};

/*
 * Effect output
 */
void
Reverb::out (REALTYPE * smps_l, REALTYPE * smps_r)
{
  int i;

  for (i = 0; i < PERIOD; i++)
    {
      inputbuf[i] = (smps_l[i] + smps_r[i]) / 2.0;
      //Initial delay r
      if (idelay != NULL)
      {
        REALTYPE tmp = inputbuf[i] + idelay[idelayk] * idelayfb;
        inputbuf[i] = idelay[idelayk];
        idelay[idelayk] = tmp;
        idelayk++;
        if (idelayk >= idelaylen)
          idelayk = 0;
      };
    };


  if (lpf != NULL)
    lpf->filterout (inputbuf);
  if (hpf != NULL)
    hpf->filterout (inputbuf);

  processmono (0, efxoutl);   //left
  processmono (1, efxoutr);   //right



  REALTYPE lvol = rs / REV_COMBS * pan;
  REALTYPE rvol = rs / REV_COMBS * (1.0 - pan);
  lvol *= 2;
  rvol *= 2;

  for (int i = 0; i < PERIOD; i++)
    {
      efxoutl[i] *= lvol;
      efxoutr[i] *= rvol;


    };
};


/*
 * Parameter control
 */
void
Reverb::setvolume (unsigned char Pvolume)
{
  this->Pvolume = Pvolume;
  volume = outvolume = Pvolume / 127.0;
  if (Pvolume == 0)
    cleanup ();


};

void
Reverb::setpan (unsigned char Ppan)
{
  this->Ppan = Ppan;
  pan = (REALTYPE) Ppan / 127.0;
};

void
Reverb::settime (unsigned char Ptime)
{
  int i;
  REALTYPE t;
  this->Ptime = Ptime;
  t = powf (60.0, (REALTYPE) Ptime / 127.0) - 0.97;

  for (i = 0; i < REV_COMBS * 2; i++)
    {
      combfb[i] =
      -expf ((REALTYPE) comblen[i] / (REALTYPE) SAMPLE_RATE * logf (0.001) /
            t);
      //the feedback is negative because it removes the DC
    };
};

void
Reverb::setlohidamp (unsigned char Plohidamp)
{
  REALTYPE x;

  if (Plohidamp < 64)
    Plohidamp = 64;           //remove this when the high part from lohidamp will be added

  this->Plohidamp = Plohidamp;
  if (Plohidamp == 64)
    {
      lohidamptype = 0;
      lohifb = 0.0;
    }
  else
    {
      if (Plohidamp < 64)
      lohidamptype = 1;
      if (Plohidamp > 64)
      lohidamptype = 2;
      x = fabsf ((REALTYPE) (Plohidamp - 64) / 64.1);
      lohifb = x * x;
    };
};

void
Reverb::setidelay (unsigned char Pidelay)
{
  REALTYPE delay;
  this->Pidelay = Pidelay;
  delay = powf (50 * Pidelay / 127.0, 2) - 1.0;

  if (idelay != NULL)
    delete (idelay);
  idelay = NULL;

  idelaylen = (int) (SAMPLE_RATE * delay / 1000);
  if (idelaylen > 1)
    {
      idelayk = 0;
      idelay = new REALTYPE[idelaylen];
      for (int i = 0; i < idelaylen; i++)
      idelay[i] = 0.0;
    };
};

void
Reverb::setidelayfb (unsigned char Pidelayfb)
{
  this->Pidelayfb = Pidelayfb;
  idelayfb = Pidelayfb / 128.0;
};

void
Reverb::sethpf (unsigned char Phpf)
{
  this->Phpf = Phpf;
  if (Phpf == 0)
    {                   //No HighPass
      if (hpf != NULL)
      delete (hpf);
      hpf = NULL;
    }
  else
    {
      REALTYPE fr = expf (powf (Phpf / 127.0, 0.5) * logf (10000.0)) + 20.0;
      if (hpf == NULL)
      hpf = new AnalogFilter (3, fr, 1, 0);
      else
      hpf->setfreq (fr);
    };
};

void
Reverb::setlpf (unsigned char Plpf)
{
  this->Plpf = Plpf;
  if (Plpf == 127)
    {                   //No LowPass
      if (lpf != NULL)
      delete (lpf);
      lpf = NULL;
    }
  else
    {
      REALTYPE fr = expf (powf (Plpf / 127.0, 0.5) * logf (25000.0)) + 40;
      if (lpf == NULL)
      lpf = new AnalogFilter (2, fr, 1, 0);
      else
      lpf->setfreq (fr);
    };
};

void
Reverb::settype (unsigned char Ptype)
{
  const int NUM_TYPES = 2;
  int combtunings[NUM_TYPES][REV_COMBS] = {
    //this is unused (for random)
    {0, 0, 0, 0, 0, 0, 0, 0},
    //Freeverb by Jezar at Dreampoint
    {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617}
  };
  int aptunings[NUM_TYPES][REV_APS] = {
    //this is unused (for random)
    {0, 0, 0, 0},
    //Freeverb by Jezar at Dreampoint
    {225, 341, 441, 556}
  };

  if (Ptype >= NUM_TYPES)
    Ptype = NUM_TYPES - 1;
  this->Ptype = Ptype;

  REALTYPE tmp;
  for (int i = 0; i < REV_COMBS * 2; i++)
    {
      if (Ptype == 0)
      tmp = 800.0 + (int) (RND * 1400.0);
      else
      tmp = combtunings[Ptype][i % REV_COMBS];
      tmp *= roomsize;
      if (i > REV_COMBS)
      tmp += 23.0;
      tmp *= SAMPLE_RATE / 44100.0; //adjust the combs according to the samplerate
      if (tmp < 10)
      tmp = 10;

      comblen[i] = (int) tmp;
      combk[i] = 0;
      lpcomb[i] = 0;
      if (comb[i] != NULL)
      delete comb[i];
      comb[i] = new REALTYPE[comblen[i]];
    };

  for (int i = 0; i < REV_APS * 2; i++)
    {
      if (Ptype == 0)
      tmp = 500 + (int) (RND * 500);
      else
      tmp = aptunings[Ptype][i % REV_APS];
      tmp *= roomsize;
      if (i > REV_APS)
      tmp += 23.0;
      tmp *= SAMPLE_RATE / 44100.0; //adjust the combs according to the samplerate
      if (tmp < 10)
      tmp = 10;
      aplen[i] = (int) tmp;
      apk[i] = 0;
      if (ap[i] != NULL)
      delete ap[i];
      ap[i] = new REALTYPE[aplen[i]];
    };
  settime (Ptime);
  cleanup ();
};

void
Reverb::setroomsize (unsigned char Proomsize)
{
  if (Proomsize == 0)
    Proomsize = 64;           //this is because the older versions consider roomsize=0
  this->Proomsize = Proomsize;
  roomsize = (Proomsize - 64.0) / 64.0;
  if (roomsize > 0.0)
    roomsize *= 2.0;
  roomsize = powf (10.0, roomsize);
  rs = sqrtf (roomsize);
  settype (Ptype);
};

void
Reverb::setpreset (unsigned char npreset)
{
  const int PRESET_SIZE = 12;
  const int NUM_PRESETS = 13;
  unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
    //Cathedral1
    {80, 64, 63, 24, 0, 0, 0, 85, 5, 83, 1, 64},
    //Cathedral2
    {80, 64, 69, 35, 0, 0, 0, 127, 0, 71, 0, 64},
    //Cathedral3
    {80, 64, 69, 24, 0, 0, 0, 127, 75, 78, 1, 85},
    //Hall1
    {90, 64, 51, 10, 0, 0, 0, 127, 21, 78, 1, 64},
    //Hall2
    {90, 64, 53, 20, 0, 0, 0, 127, 75, 71, 1, 64},
    //Room1
    {100, 64, 33, 0, 0, 0, 0, 127, 0, 106, 0, 30},
    //Room2
    {100, 64, 21, 26, 0, 0, 0, 62, 0, 77, 1, 45},
    //Basement
    {110, 64, 14, 0, 0, 0, 0, 127, 5, 71, 0, 25},
    //Tunnel
    {85, 80, 84, 20, 42, 0, 0, 51, 0, 78, 1, 105},
    //Echoed1
    {95, 64, 26, 60, 71, 0, 0, 114, 0, 64, 1, 64},
    //Echoed2
    {90, 64, 40, 88, 71, 0, 0, 114, 0, 88, 1, 64},
    //VeryLong1
    {90, 64, 93, 15, 0, 0, 0, 114, 0, 77, 0, 95},
    //VeryLong2
    {90, 64, 111, 30, 0, 0, 0, 114, 90, 74, 1, 80}
  };

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


void
Reverb::changepar (int npar, unsigned char value)
{
  switch (npar)
    {
    case 0:
      setvolume (value);
      break;
    case 1:
      setpan (value);
      break;
    case 2:
      settime (value);
      break;
    case 3:
      setidelay (value);
      break;
    case 4:
      setidelayfb (value);
      break;
//      case 5: setrdelay(value);
//              break;
//      case 6: seterbalance(value);
//              break;
    case 7:
      setlpf (value);
      break;
    case 8:
      sethpf (value);
      break;
    case 9:
      setlohidamp (value);
      break;
    case 10:
      settype (value);
      break;
    case 11:
      setroomsize (value);
      break;
    };
};

unsigned char
Reverb::getpar (int npar)
{
  switch (npar)
    {
    case 0:
      return (Pvolume);
      break;
    case 1:
      return (Ppan);
      break;
    case 2:
      return (Ptime);
      break;
    case 3:
      return (Pidelay);
      break;
    case 4:
      return (Pidelayfb);
      break;
//      case 5: return(Prdelay);
//              break;
//      case 6: return(Perbalance);
//              break;
    case 7:
      return (Plpf);
      break;
    case 8:
      return (Phpf);
      break;
    case 9:
      return (Plohidamp);
      break;
    case 10:
      return (Ptype);
      break;
    case 11:
      return (Proomsize);
      break;
    };
  return (0);                 //in case of bogus "parameter"
};

Generated by  Doxygen 1.6.0   Back to index